From 63e15077126b036b772997bd68f518038f2ffd0f Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 28 Jun 2023 13:16:16 +0000 Subject: [PATCH 01/73] Delete outdated testing files --- .../tests/testthat/client_infrastructure.R | 32 ------------------- R/rdeephaven/tests/testthat/test_client.R | 1 - 2 files changed, 33 deletions(-) delete mode 100644 R/rdeephaven/tests/testthat/client_infrastructure.R delete mode 100644 R/rdeephaven/tests/testthat/test_client.R diff --git a/R/rdeephaven/tests/testthat/client_infrastructure.R b/R/rdeephaven/tests/testthat/client_infrastructure.R deleted file mode 100644 index 309e719a52e..00000000000 --- a/R/rdeephaven/tests/testthat/client_infrastructure.R +++ /dev/null @@ -1,32 +0,0 @@ -generate_dataframes <- function() { - df1 <- data.frame(string_col = c("I", "am", "a", "string", "column"), - int_col = c(0, 1, 2, 3, 4), - dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00)) - - df2 <- data.frame(col1 = rep(3.14, 100), - col2 = rep("hello!", 100), - col3 = rnorm(100)) - - df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) - - df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[2500000], - bool_col = sample(c(TRUE, FALSE), 2500000, TRUE), - int_col = sample(0:100000, 2500000, TRUE)) - - return(list(df1, df2, df3, df4)) -} - -setup_client <- function(target, dataframes=NULL) { - - client_options <- ClientOptions$new() - client_options$set_default_authentication() - client <- Client$new(target=target, client_options=client_options)) - - if (!is.null(dataframes)) { - for (i in 1:length(dataframes)) { - th = client$import_table(dataframes[i]) - th$bind_to_variable(paste0("table", i)) - } - } - return(client) -} diff --git a/R/rdeephaven/tests/testthat/test_client.R b/R/rdeephaven/tests/testthat/test_client.R deleted file mode 100644 index 17021e26580..00000000000 --- a/R/rdeephaven/tests/testthat/test_client.R +++ /dev/null @@ -1 +0,0 @@ -# TODO: TEST CLIENT CLASS \ No newline at end of file From 46ce7f44eaacc45981199f13c0475c80a67f1144 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 29 Jun 2023 19:14:42 +0000 Subject: [PATCH 02/73] Continue api expansion --- R/rdeephaven/src/client.cpp | 68 ++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 121450fd838..c7f62c9b63d 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -23,7 +23,69 @@ class TableHandleWrapper { public: TableHandleWrapper(deephaven::client::TableHandle ref_table) : internal_tbl_hdl(std::move(ref_table)) {}; - // TODO: DEEPHAVEN QUERY METHODS WILL GO HERE + TableHandleWrapper* select(std::vector columnSpecs) {}; + + TableHandleWrapper* view(std::vector columnSpecs) {}; + + TableHandleWrapper* dropColumns(std::vector columnSpecs) {}; + + TableHandleWrapper* update(std::vector columnSpecs) {}; + + TableHandleWrapper* updateView(std::vector columnSpecs) {}; + + TableHandleWrapper* where(std::string condition) {}; + + // TODO: TableHandleWrapper* sort(std::vector sortPairs) {}; + + TableHandleWrapper* by(std::vector columnSpecs) {}; + + // TODO: TableHandleWrapper* by(AggregateCombo combo, std::vector groupByColumns) {}; + + TableHandleWrapper* minBy(std::vector columnSpecs) {}; + + TableHandleWrapper* maxBy(std::vector columnSpecs) {}; + + TableHandleWrapper* sumBy(std::vector columnSpecs) {}; + + TableHandleWrapper* absSumBy(std::vector columnSpecs) {}; + + TableHandleWrapper* varBy(std::vector columnSpecs) {}; + + TableHandleWrapper* stdBy(std::vector columnSpecs) {}; + + TableHandleWrapper* avgBy(std::vector columnSpecs) {}; + + TableHandleWrapper* firstBy(std::vector columnSpecs) {}; + + TableHandleWrapper* lastBy(std::vector columnSpecs) {}; + + TableHandleWrapper* medianBy(std::vector columnSpecs) {}; + + TableHandleWrapper* percentileBy(double percentile, std::vector columnSpecs) {}; + + TableHandleWrapper* percentileBy(double percentile, bool avgMedian, std::vector columnSpecs) {}; + + TableHandleWrapper* countBy(std::string countByColumn, std::vector columnSpecs) {}; + + TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) {}; + + TableHandleWrapper* tailBy(int64_t n, std::vector columnSpecs) {}; + + TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) {}; + + TableHandleWrapper* head(int64_t n) {}; + + TableHandleWrapper* tail(int64_t n) {}; + + TableHandleWrapper* ungroup(bool nullFill, std::vector groupByColumns) {}; + + TableHandleWrapper* merge(std::string keyColumn, std::vector sources) {}; + + TableHandleWrapper* merge(std::vector sources) {}; + + TableHandleWrapper* naturalJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) {}; + + TableHandleWrapper* exactJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) {}; /** * Whether the table was static at the time internal_tbl_hdl was created. @@ -116,6 +178,10 @@ class ClientWrapper { return new TableHandleWrapper(internal_tbl_hdl_mngr.fetchTable(tableName)); } + TableHandleWrapper* emptyTable(int64_t size) {}; + + TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) {}; + /** * Runs a script on the server in the console language if a console was created. * @param code String of the code to be executed on the server. From 28f87a27713883be5ef915f9e83561495e900fa2 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 6 Jul 2023 17:03:36 -0500 Subject: [PATCH 03/73] More api stuff --- R/rdeephaven/R/table_handle_wrapper.R | 142 ++++++++++++++++++++-- R/rdeephaven/src/client.cpp | 165 ++++++++++++++++++++------ 2 files changed, 266 insertions(+), 41 deletions(-) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 6464abbd0c4..9403b53ea67 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -34,8 +34,135 @@ TableHandle <- R6Class("TableHandle", stop("'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") } - private$internal_table_handle <- table_handle - private$is_static_field <- private$internal_table_handle$is_static() + self$internal_table_handle <- table_handle + private$is_static_field <- self$internal_table_handle$is_static() + }, + + select = function(columns) { + return(TableHandle$new(self$internal_table_handle$select(columns))) + }, + + view = function(columns) { + return(TableHandle$new(self$internal_table_handle$view(columns))) + }, + + drop_columns = function(columns) { + return(TableHandle$new(self$internal_table_handle$drop_columns(columns))) + }, + + update = function(columns) { + return(TableHandle$new(self$internal_table_handle$update(columns))) + }, + + update_view = function(columns) { + return(TableHandle$new(self$internal_table_handle$update_view(columns))) + }, + + where = function(condition) { + return(TableHandle$new(self$internal_table_handle$where(condition))) + }, + + # TODO: sort = function(sort_pairs) { + # return(TableHandle$new(self$internal_table_handle$sort(sort_pairs))) + #}, + + by = function(columns) { + return(TableHandle$new(self$internal_table_handle$by(columns))) + }, + + min_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$min_by(columns))) + }, + + max_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$max_by(columns))) + }, + + sum_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$sum_by(columns))) + }, + + abs_sum_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$abs_sum_by(columns))) + }, + + var_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$var_by(columns))) + }, + + std_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$std_by(columns))) + }, + + avg_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$avg_by(columns))) + }, + + first_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$first_by(columns))) + }, + + last_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$last_by(columns))) + }, + + median_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$median_by(columns))) + }, + + percentile_by = function(percentile, columns) { + return(TableHandle$new(self$internal_table_handle$percentile_by(percentile, columns))) + }, + + count_by = function(count_by_column, columns) { + return(TableHandle$new(self$internal_table_handle$count_by(count_by_column, columns))) + }, + + w_avg_by = function(weight_column, columns) { + return(TableHandle$new(self$internal_table_handle$w_avg_by(weight_column, columns))) + }, + + tail_by = function(n, columns) { + return(TableHandle$new(self$internal_table_handle$tail_by(n, columns))) + }, + + head_by = function(n, columns) { + return(TableHandle$new(self$internal_table_handle$head_by(n, columns))) + }, + + head = function(n) { + return(TableHandle$new(self$internal_table_handle$head(n))) + }, + + tail = function(n) { + return(TableHandle$new(self$internal_table_handle$tail(n))) + }, + + ungroup = function(null_fill, group_by_columns) { + return(TableHandle$new(self$internal_table_handle$ungroup(null_fill, group_by_columns))) + }, + + #TODO: merge = function(key_column, sources) { + # return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) + #}, + + cross_join = function(right_side, columns_to_match, columns_to_add) { + return(TableHandle$new(self$internal_table_handle$cross_join(right_side$internal_table_handle, + columns_to_match, columns_to_add))) + }, + + natural_join = function(right_side, columns_to_match, columns_to_add) { + return(TableHandle$new(self$internal_table_handle$natural_join(right_side$internal_table_handle, + columns_to_match, columns_to_add))) + }, + + exact_join = function(right_side, columns_to_match, columns_to_add) { + print(right_side) + print(columns_to_match) + print(columns_to_add) + print(right_side$internal_table_handle) + return(TableHandle$new(self$internal_table_handle$exact_join(right_side$internal_table_handle, + columns_to_match, columns_to_add))) }, #' @description @@ -52,7 +179,7 @@ TableHandle <- R6Class("TableHandle", if(!private$is_static_field) { stop("The number of rows is not yet supported for dynamic tables.") } - return(private$internal_table_handle$num_rows()) + return(self$internal_table_handle$num_rows()) }, #' @description @@ -61,14 +188,14 @@ TableHandle <- R6Class("TableHandle", #' @param name Name for this table on the server. bind_to_variable = function(name) { .verify_string("name", name) - private$internal_table_handle$bind_to_variable(name) + self$internal_table_handle$bind_to_variable(name) }, #' @description #' Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. #' @return A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. to_arrow_record_batch_stream_reader = function() { - ptr = private$internal_table_handle$get_arrow_array_stream_ptr() + ptr = self$internal_table_handle$get_arrow_array_stream_ptr() rbsr = RecordBatchStreamReader$import_from_c(ptr) return(rbsr) }, @@ -97,10 +224,11 @@ TableHandle <- R6Class("TableHandle", to_data_frame = function() { arrow_tbl = self$to_arrow_table() return(as.data.frame(as.data.frame(arrow_tbl))) # TODO: for some reason as.data.frame on arrow table returns a tibble, not a data frame - } + }, + + internal_table_handle = NULL ), private = list( - internal_table_handle = NULL, is_static_field = NULL ) ) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index f174fd48e63..5ed7a1bfaa6 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -23,69 +23,136 @@ class TableHandleWrapper { public: TableHandleWrapper(deephaven::client::TableHandle ref_table) : internal_tbl_hdl(std::move(ref_table)) {}; - TableHandleWrapper* select(std::vector columnSpecs) {}; + // HELPER FUNCTIONS - TableHandleWrapper* view(std::vector columnSpecs) {}; + std::vector convertTableHandleWrapperVector(std::vector input) { + std::vector output(input.size()); + std::transform(input.begin(), input.end(), + output.begin(), [](const TableHandleWrapper& wrapper) { return wrapper.internal_tbl_hdl; }); + return output; + }; - TableHandleWrapper* dropColumns(std::vector columnSpecs) {}; + // TABLE OPERATIONS - TableHandleWrapper* update(std::vector columnSpecs) {}; + TableHandleWrapper* select(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.select(columnSpecs)); + }; - TableHandleWrapper* updateView(std::vector columnSpecs) {}; + TableHandleWrapper* view(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.view(columnSpecs)); + }; - TableHandleWrapper* where(std::string condition) {}; + TableHandleWrapper* dropColumns(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.dropColumns(columnSpecs)); + }; - // TODO: TableHandleWrapper* sort(std::vector sortPairs) {}; + TableHandleWrapper* update(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.update(columnSpecs)); + }; - TableHandleWrapper* by(std::vector columnSpecs) {}; + TableHandleWrapper* updateView(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.updateView(columnSpecs)); + }; - // TODO: TableHandleWrapper* by(AggregateCombo combo, std::vector groupByColumns) {}; + TableHandleWrapper* where(std::string condition) { + return new TableHandleWrapper(internal_tbl_hdl.where(condition)); + }; - TableHandleWrapper* minBy(std::vector columnSpecs) {}; + // TODO: TableHandleWrapper* sort(std::vector sortPairs) { + // return new TableHandleWrapper(internal_tbl_hdl.sort(sortPairs)); + // }; - TableHandleWrapper* maxBy(std::vector columnSpecs) {}; + TableHandleWrapper* by(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.by(columnSpecs)); + }; - TableHandleWrapper* sumBy(std::vector columnSpecs) {}; + TableHandleWrapper* minBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.minBy(columnSpecs)); + }; - TableHandleWrapper* absSumBy(std::vector columnSpecs) {}; + TableHandleWrapper* maxBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.maxBy(columnSpecs)); + }; - TableHandleWrapper* varBy(std::vector columnSpecs) {}; + TableHandleWrapper* sumBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.sumBy(columnSpecs)); + }; - TableHandleWrapper* stdBy(std::vector columnSpecs) {}; + TableHandleWrapper* absSumBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.absSumBy(columnSpecs)); + }; - TableHandleWrapper* avgBy(std::vector columnSpecs) {}; + TableHandleWrapper* varBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.varBy(columnSpecs)); + }; - TableHandleWrapper* firstBy(std::vector columnSpecs) {}; + TableHandleWrapper* stdBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.stdBy(columnSpecs)); + }; - TableHandleWrapper* lastBy(std::vector columnSpecs) {}; + TableHandleWrapper* avgBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.avgBy(columnSpecs)); + }; - TableHandleWrapper* medianBy(std::vector columnSpecs) {}; + TableHandleWrapper* firstBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.firstBy(columnSpecs)); + }; - TableHandleWrapper* percentileBy(double percentile, std::vector columnSpecs) {}; + TableHandleWrapper* lastBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.lastBy(columnSpecs)); + }; - TableHandleWrapper* percentileBy(double percentile, bool avgMedian, std::vector columnSpecs) {}; + TableHandleWrapper* medianBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.medianBy(columnSpecs)); + }; - TableHandleWrapper* countBy(std::string countByColumn, std::vector columnSpecs) {}; + TableHandleWrapper* percentileBy(double percentile, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.percentileBy(percentile, columnSpecs)); + }; - TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) {}; + TableHandleWrapper* countBy(std::string countByColumn, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.countBy(countByColumn, columnSpecs)); + }; - TableHandleWrapper* tailBy(int64_t n, std::vector columnSpecs) {}; + TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.wAvgBy(weightColumn, columnSpecs)); + }; - TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) {}; + TableHandleWrapper* tailBy(int64_t n, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.tailBy(n, columnSpecs)); + }; - TableHandleWrapper* head(int64_t n) {}; + TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); + }; - TableHandleWrapper* tail(int64_t n) {}; + TableHandleWrapper* head(int64_t n) { + return new TableHandleWrapper(internal_tbl_hdl.head(n)); + }; - TableHandleWrapper* ungroup(bool nullFill, std::vector groupByColumns) {}; + TableHandleWrapper* tail(int64_t n) { + return new TableHandleWrapper(internal_tbl_hdl.tail(n)); + }; - TableHandleWrapper* merge(std::string keyColumn, std::vector sources) {}; + TableHandleWrapper* ungroup(bool nullFill, std::vector groupByColumns) { + return new TableHandleWrapper(internal_tbl_hdl.ungroup(nullFill, groupByColumns)); + }; - TableHandleWrapper* merge(std::vector sources) {}; + // TODO: TableHandleWrapper* merge(std::string keyColumn, std::vector sources) { + // return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, convertTableHandleWrapperVector(sources))); + // }; - TableHandleWrapper* naturalJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) {}; + TableHandleWrapper* crossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.crossJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + }; - TableHandleWrapper* exactJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) {}; + TableHandleWrapper* naturalJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.naturalJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + }; + + TableHandleWrapper* exactJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.exactJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + }; /** * Whether the table was static at the time internal_tbl_hdl was created. @@ -198,9 +265,9 @@ class ClientWrapper { return new TableHandleWrapper(internal_tbl_hdl_mngr.fetchTable(tableName)); } - TableHandleWrapper* emptyTable(int64_t size) {}; + // TODO: TableHandleWrapper* emptyTable(int64_t size) {}; - TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) {}; + // TODO: TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) {}; /** * Runs a script on the server in the console language if a console was created. @@ -306,6 +373,36 @@ RCPP_EXPOSED_CLASS(ArrowArrayStream) RCPP_MODULE(DeephavenInternalModule) { class_("INTERNAL_TableHandle") + .method("select", &TableHandleWrapper::select) + .method("view", &TableHandleWrapper::view) + .method("drop_columns", &TableHandleWrapper::dropColumns) + .method("update", &TableHandleWrapper::update) + .method("update_view", &TableHandleWrapper::updateView) + .method("where", &TableHandleWrapper::where) + // TODO: .method("sort", &TableHandleWrapper::sort) + .method("by", &TableHandleWrapper::by) + .method("min_by", &TableHandleWrapper::minBy) + .method("max_by", &TableHandleWrapper::maxBy) + .method("sum_by", &TableHandleWrapper::sumBy) + .method("abs_sum_by", &TableHandleWrapper::absSumBy) + .method("var_by", &TableHandleWrapper::varBy) + .method("std_by", &TableHandleWrapper::stdBy) + .method("avg_by", &TableHandleWrapper::avgBy) + .method("first_by", &TableHandleWrapper::firstBy) + .method("last_by", &TableHandleWrapper::lastBy) + .method("median_by", &TableHandleWrapper::medianBy) + .method("percentile_by", &TableHandleWrapper::percentileBy) + .method("count_by", &TableHandleWrapper::countBy) + .method("w_avg_by", &TableHandleWrapper::wAvgBy) + .method("tail_by", &TableHandleWrapper::tailBy) + .method("head_by", &TableHandleWrapper::headBy) + .method("head", &TableHandleWrapper::head) + .method("tail", &TableHandleWrapper::tail) + .method("ungroup", &TableHandleWrapper::ungroup) + // TODO: .method("merge", &TableHandleWrapper::merge) + .method("cross_join", &TableHandleWrapper::crossJoin) + .method("natural_join", &TableHandleWrapper::naturalJoin) + .method("exact_join", &TableHandleWrapper::exactJoin) .method("is_static", &TableHandleWrapper::isStatic) .method("num_rows", &TableHandleWrapper::numRows) .method("bind_to_variable", &TableHandleWrapper::bindToVariable) From c752a1484ec291d32007f5b4d40d161c0fb73c97 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 10 Jul 2023 09:02:05 -0500 Subject: [PATCH 04/73] Continue API expansion --- R/rdeephaven/src/client.cpp | 56 +++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 5ed7a1bfaa6..19e56823660 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -34,6 +34,8 @@ class TableHandleWrapper { // TABLE OPERATIONS + // FILTER OPERATIONS + TableHandleWrapper* select(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.select(columnSpecs)); }; @@ -58,9 +60,7 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.where(condition)); }; - // TODO: TableHandleWrapper* sort(std::vector sortPairs) { - // return new TableHandleWrapper(internal_tbl_hdl.sort(sortPairs)); - // }; + // AGGREGATION OPERATIONS TableHandleWrapper* by(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.by(columnSpecs)); @@ -126,6 +126,22 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); }; + // JOIN OPERATIONS + + TableHandleWrapper* crossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.crossJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + }; + + TableHandleWrapper* naturalJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.naturalJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + }; + + TableHandleWrapper* exactJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.exactJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + }; + + // MISC OPERATIONS + TableHandleWrapper* head(int64_t n) { return new TableHandleWrapper(internal_tbl_hdl.head(n)); }; @@ -138,22 +154,14 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.ungroup(nullFill, groupByColumns)); }; + // TODO: TableHandleWrapper* sort(std::vector sortPairs) { + // return new TableHandleWrapper(internal_tbl_hdl.sort(sortPairs)); + // }; + // TODO: TableHandleWrapper* merge(std::string keyColumn, std::vector sources) { // return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, convertTableHandleWrapperVector(sources))); // }; - TableHandleWrapper* crossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { - return new TableHandleWrapper(internal_tbl_hdl.crossJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); - }; - - TableHandleWrapper* naturalJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { - return new TableHandleWrapper(internal_tbl_hdl.naturalJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); - }; - - TableHandleWrapper* exactJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { - return new TableHandleWrapper(internal_tbl_hdl.exactJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); - }; - /** * Whether the table was static at the time internal_tbl_hdl was created. */ @@ -265,9 +273,13 @@ class ClientWrapper { return new TableHandleWrapper(internal_tbl_hdl_mngr.fetchTable(tableName)); } - // TODO: TableHandleWrapper* emptyTable(int64_t size) {}; + TableHandleWrapper* emptyTable(int64_t size) { + return new TableHandleWrapper(internal_tbl_hdl_mngr.emptyTable(size)); + } - // TODO: TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) {}; + TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) { + return new TableHandleWrapper(internal_tbl_hdl_mngr.timeTable(startTimeNanos, periodNanos)); + }; /** * Runs a script on the server in the console language if a console was created. @@ -379,7 +391,6 @@ RCPP_MODULE(DeephavenInternalModule) { .method("update", &TableHandleWrapper::update) .method("update_view", &TableHandleWrapper::updateView) .method("where", &TableHandleWrapper::where) - // TODO: .method("sort", &TableHandleWrapper::sort) .method("by", &TableHandleWrapper::by) .method("min_by", &TableHandleWrapper::minBy) .method("max_by", &TableHandleWrapper::maxBy) @@ -396,13 +407,14 @@ RCPP_MODULE(DeephavenInternalModule) { .method("w_avg_by", &TableHandleWrapper::wAvgBy) .method("tail_by", &TableHandleWrapper::tailBy) .method("head_by", &TableHandleWrapper::headBy) + .method("cross_join", &TableHandleWrapper::crossJoin) + .method("natural_join", &TableHandleWrapper::naturalJoin) + .method("exact_join", &TableHandleWrapper::exactJoin) .method("head", &TableHandleWrapper::head) .method("tail", &TableHandleWrapper::tail) .method("ungroup", &TableHandleWrapper::ungroup) + // TODO: .method("sort", &TableHandleWrapper::sort) // TODO: .method("merge", &TableHandleWrapper::merge) - .method("cross_join", &TableHandleWrapper::crossJoin) - .method("natural_join", &TableHandleWrapper::naturalJoin) - .method("exact_join", &TableHandleWrapper::exactJoin) .method("is_static", &TableHandleWrapper::isStatic) .method("num_rows", &TableHandleWrapper::numRows) .method("bind_to_variable", &TableHandleWrapper::bindToVariable) @@ -425,6 +437,8 @@ RCPP_MODULE(DeephavenInternalModule) { class_("INTERNAL_Client") .factory(newClientWrapper) .method("open_table", &ClientWrapper::openTable) + .method("empty_table", &ClientWrapper::emptyTable) + .method("time_table", &ClientWrapper::timeTable) .method("check_for_table", &ClientWrapper::checkForTable) .method("run_script", &ClientWrapper::runScript) .method("new_arrow_array_stream_ptr", &ClientWrapper::newArrowArrayStreamPtr) From acf9aedd9b278325c1b4480e18a6f74d50b39306 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 13 Jul 2023 15:31:13 -0500 Subject: [PATCH 05/73] Document new methods, start unit testing file. Roxygen not called yet --- R/rdeephaven/R/table_handle_wrapper.R | 208 ++++++++++++++++-- .../tests/testthat/test_table_operations.R | 139 ++++++++++++ 2 files changed, 329 insertions(+), 18 deletions(-) create mode 100644 R/rdeephaven/tests/testthat/test_table_operations.R diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 9403b53ea67..a0876c23fb8 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -36,126 +36,251 @@ TableHandle <- R6Class("TableHandle", } self$internal_table_handle <- table_handle private$is_static_field <- self$internal_table_handle$is_static() + print("initializing!") }, + # FILTERING OPERATIONS + + #' @description + #' Select columns from a table. The columns can be column names or formulas like + #' "NewCol = A + 12". See the Deephaven documentation for the difference between "select" and "view". + #' @param columns The columns to select. + #' @return A TableHandle referencing the new table. select = function(columns) { return(TableHandle$new(self$internal_table_handle$select(columns))) }, + #' @description + #' View columns from a table. The columns can be column names or formulas like + #' "NewCol = A + 12". See the Deephaven documentation for the difference between select() and view(). + #' @param columns The columns to view. + #' @return A TableHandle referencing the new table. view = function(columns) { return(TableHandle$new(self$internal_table_handle$view(columns))) }, + #' @description + #' Creates a new table from this table where the specified columns have been excluded. + #' @param columns The columns to exclude. + #' @return A TableHandle referencing the new table. drop_columns = function(columns) { return(TableHandle$new(self$internal_table_handle$drop_columns(columns))) }, + #' @description + #' Creates a new table from this table, but including the additional specified columns. + #' See the Deephaven documentation for the difference between update() and updateView(). + #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. + #' @return A TableHandle referencing the new table. update = function(columns) { return(TableHandle$new(self$internal_table_handle$update(columns))) }, + #' @description + #' Creates a new view from this table, but including the additional specified columns. + #' See the Deephaven documentation for the difference between update() and updateView(). + #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. + #' @return A TableHandle referencing the new table. update_view = function(columns) { return(TableHandle$new(self$internal_table_handle$update_view(columns))) }, + #' @description + #' Creates a new table from this table, filtered by condition. Consult the Deephaven + #' documentation for more information about valid conditions. + #' @param condition A Deephaven boolean expression such as "Price > 100" or "Col3 == Col1 * Col2". + #' @return A TableHandle referencing the new table. where = function(condition) { return(TableHandle$new(self$internal_table_handle$where(condition))) }, - # TODO: sort = function(sort_pairs) { - # return(TableHandle$new(self$internal_table_handle$sort(sort_pairs))) - #}, + # AGGREGATION OPERATIONS + #' @description + #' Creates a new table from this table, grouped by columns with the column content grouped + #' into arrays. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. by = function(columns) { return(TableHandle$new(self$internal_table_handle$by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "min" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. min_by = function(columns) { return(TableHandle$new(self$internal_table_handle$min_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "max" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. max_by = function(columns) { return(TableHandle$new(self$internal_table_handle$max_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "sum" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. sum_by = function(columns) { return(TableHandle$new(self$internal_table_handle$sum_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "absSum" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. abs_sum_by = function(columns) { return(TableHandle$new(self$internal_table_handle$abs_sum_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "var" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. var_by = function(columns) { return(TableHandle$new(self$internal_table_handle$var_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "std" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. std_by = function(columns) { return(TableHandle$new(self$internal_table_handle$std_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "avg" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. avg_by = function(columns) { return(TableHandle$new(self$internal_table_handle$avg_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "first" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. first_by = function(columns) { return(TableHandle$new(self$internal_table_handle$first_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "last" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. last_by = function(columns) { return(TableHandle$new(self$internal_table_handle$last_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "median" aggregate operation + #' applied to the remaining columns. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. median_by = function(columns) { return(TableHandle$new(self$internal_table_handle$median_by(columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, with the "percentile" aggregate operation + #' applied to the remaining columns. + #' @param percentile The designated percentile + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. percentile_by = function(percentile, columns) { return(TableHandle$new(self$internal_table_handle$percentile_by(percentile, columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, having a new column named by + #' `countByColumn` containing the size of each group. + #' @param count_by_column Name of the output column. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. count_by = function(count_by_column, columns) { return(TableHandle$new(self$internal_table_handle$count_by(count_by_column, columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, having a new column named by + #' `weightColumn` containing the weighted average of each group. + #' @param weight_column Name of the output column. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. w_avg_by = function(weight_column, columns) { return(TableHandle$new(self$internal_table_handle$w_avg_by(weight_column, columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, containing the last `n` rows of + #' each group. + #' @param n Number of rows + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. tail_by = function(n, columns) { return(TableHandle$new(self$internal_table_handle$tail_by(n, columns))) }, + #' @description + #' Creates a new table from this table, grouped by columns, containing the first `n` rows of + #' each group. + #' @param n Number of rows + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. head_by = function(n, columns) { return(TableHandle$new(self$internal_table_handle$head_by(n, columns))) }, - head = function(n) { - return(TableHandle$new(self$internal_table_handle$head(n))) - }, - - tail = function(n) { - return(TableHandle$new(self$internal_table_handle$tail(n))) - }, - - ungroup = function(null_fill, group_by_columns) { - return(TableHandle$new(self$internal_table_handle$ungroup(null_fill, group_by_columns))) - }, - - #TODO: merge = function(key_column, sources) { - # return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) - #}, + # JOIN OPERATIONS + #' @description + #' Creates a new table by cross joining this table with `rightSide`. The tables are joined by + #' the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally + #' renamed by `columnsToAdd`. Example: + #' @param right_side The table to join with this table + #' @param columns_to_match The columns to join on + #' @param columns_to_add The columns from the right side to add, and possibly rename. + #' @return A TableHandle referencing the new table. cross_join = function(right_side, columns_to_match, columns_to_add) { return(TableHandle$new(self$internal_table_handle$cross_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, + #' @description + #' Creates a new table by natural joining this table with `rightSide`. The tables are joined by + #' the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally + #' renamed by `columnsToAdd`. Example: + #' @param right_side The table to join with this table + #' @param columns_to_match The columns to join on + #' @param columns_to_add The columns from the right side to add, and possibly rename. + #' @return A TableHandle referencing the new table. natural_join = function(right_side, columns_to_match, columns_to_add) { return(TableHandle$new(self$internal_table_handle$natural_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, + #' @description + #' Creates a new table by exact joining this table with `rightSide`. The tables are joined by + #' the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally + #' renamed by `columnsToAdd`. Example: + #' @param right_side The table to join with this table + #' @param columns_to_match The columns to join on + #' @param columns_to_add The columns from the right side to add, and possibly rename. + #' @return A TableHandle referencing the new table. exact_join = function(right_side, columns_to_match, columns_to_add) { print(right_side) print(columns_to_match) @@ -165,6 +290,53 @@ TableHandle <- R6Class("TableHandle", columns_to_match, columns_to_add))) }, + # MISC OPERATIONS + + #' @description + #' Creates a new table from this table containing the first `n` rows of this table. + #' @param n Number of rows + #' @return A TableHandle referencing the new table. + head = function(n) { + return(TableHandle$new(self$internal_table_handle$head(n))) + }, + + #' @description + #' Creates a new table from this table containing the last `n` rows of this table. + #' @param n Number of rows + #' @return A TableHandle referencing the new table. + tail = function(n) { + return(TableHandle$new(self$internal_table_handle$tail(n))) + }, + + #' @description + #' Creates a new table from this table with the column array data ungrouped. This is the inverse + #' of the by() const operation. + #' @param group_by_columns Columns to ungroup. + #' @return A TableHandle referencing the new table. + ungroup = function(null_fill, group_by_columns) { + return(TableHandle$new(self$internal_table_handle$ungroup(null_fill, group_by_columns))) + }, + + #' @description + #' Creates a new table from this table, sorted by sortPairs. + #' @param sort_pairs A vector of SortPair objects describing the sort. Each SortPair refers to + #' a column, a sort direction, and whether the sort should consider to the value's regular or + #' absolute value when doing comparisons. + #' @return A TableHandle referencing the new table. + # TODO: sort = function(sort_pairs) { + # return(TableHandle$new(self$internal_table_handle$sort(sort_pairs))) + #}, + + #' @description + #' Creates a new table by merging `sources` together. The tables are essentially stacked on top + #' of each other. + #TODO: Document keyColumn + #' @param sources The tables to merge. + #' @return A TableHandle referencing the new table. + #TODO: merge = function(key_column, sources) { + # return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) + #}, + #' @description #' Whether the table referenced by this TableHandle is static or not. #' @return TRUE if the table is static, or FALSE if the table is ticking. diff --git a/R/rdeephaven/tests/testthat/test_table_operations.R b/R/rdeephaven/tests/testthat/test_table_operations.R new file mode 100644 index 00000000000..7fa68d00da9 --- /dev/null +++ b/R/rdeephaven/tests/testthat/test_table_operations.R @@ -0,0 +1,139 @@ +library(testthat) +library(rdeephaven) + +setup <- function() { + + df1 <- data.frame(string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00)) + + df2 <- data.frame(col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100)) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE)) + + # in order to test TableHandle, we need to have tables on the server that we know everything about. + # thus, we have to push these created tables to the server and get TableHandles to each of them. + # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() + + # set up client + client_options <- ClientOptions$new() + client <- Client$new(target="localhost:10000", client_options=client_options) + + # move dataframes to server and get TableHandles for testing + th1 <- client$import_table(df1) + th2 <- client$import_table(df2) + th3 <- client$import_table(df3) + th4 <- client$import_table(df4) + + return(list("client" = client, + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4)) +} + +##### TESTING GOOD INPUTS ##### + +test_that("select behaves as expected", { + data <- setup() +}) + +test_that("view behaves as expected", { + data <- setup() +}) + +test_that("drop_columns behaves as expected", { + data <- setup() +}) + +test_that("update behaves as expected", { + data <- setup() +}) + +test_that("update_view behaves as expected", { + data <- setup() +}) + +test_that("where behaves as expected", { + data <- setup() +}) + +test_that("by behaves as expected", { + data <- setup() +}) + +test_that("min_by behaves as expected", { + data <- setup() +}) + +test_that("max_by behaves as expected", { + data <- setup() +}) + +test_that("sum_by behaves as expected", { + data <- setup() +}) + +test_that("abs_sum_by behaves as expected", { + data <- setup() +}) + +test_that("var_by behaves as expected", { + data <- setup() +}) + +test_that("std_by behaves as expected", { + data <- setup() +}) + +test_that("avg_by behaves as expected", { + data <- setup() +}) + +test_that("first_by behaves as expected", { + data <- setup() +}) + +test_that("last_by behaves as expected", { + data <- setup() +}) + +test_that("median_by behaves as expected", { + data <- setup() +}) + +test_that("percentile_by behaves as expected", { + data <- setup() +}) + +test_that("count_by behaves as expected", { + data <- setup() +}) + +test_that("w_avg_by behaves as expected", { + data <- setup() +}) + +test_that("tail_by behaves as expected", { + data <- setup() +}) + +test_that("head_by behaves as expected", { + data <- setup() +}) + +test_that("cross_join behaves as expected", { + data <- setup() +}) + +test_that("natural_join behaves as expected", { + data <- setup() +}) + +test_that("exact_join behaves as expected", { + data <- setup() +}) From 1d32d0568026d214cbc368f789d972cb0afc1402 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 13 Jul 2023 16:50:22 -0500 Subject: [PATCH 06/73] Rearrange methods, change gitignore, generate roxygen --- R/rdeephaven/.gitignore | 4 +- R/rdeephaven/R/table_handle_wrapper.R | 124 ++--- R/rdeephaven/man/ClientOptions.Rd | 12 +- R/rdeephaven/man/TableHandle.Rd | 658 +++++++++++++++++++++++++- 4 files changed, 734 insertions(+), 64 deletions(-) diff --git a/R/rdeephaven/.gitignore b/R/rdeephaven/.gitignore index 9f651736392..ad4856e82ab 100644 --- a/R/rdeephaven/.gitignore +++ b/R/rdeephaven/.gitignore @@ -2,4 +2,6 @@ lib/cpp-client/ lib/cpp-examples/ lib/cpp-dependencies/local lib/cpp-dependencies/src -lib/cpp-dependencies/env.sh \ No newline at end of file +lib/cpp-dependencies/env.sh +*.o +*.so diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index a0876c23fb8..9c157447b13 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -39,6 +39,69 @@ TableHandle <- R6Class("TableHandle", print("initializing!") }, + #' @description + #' Whether the table referenced by this TableHandle is static or not. + #' @return TRUE if the table is static, or FALSE if the table is ticking. + is_static = function() { + return(private$is_static_field) + }, + + #' @description + #' Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. + #' @return The number of rows in the table. + nrow = function() { + if(!private$is_static_field) { + stop("The number of rows is not yet supported for dynamic tables.") + } + return(self$internal_table_handle$num_rows()) + }, + + #' @description + #' Binds the table referenced by this TableHandle to a variable on the server, + #' enabling it to be accessed by that name from any Deephaven API. + #' @param name Name for this table on the server. + bind_to_variable = function(name) { + .verify_string("name", name) + self$internal_table_handle$bind_to_variable(name) + }, + + #' @description + #' Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. + #' @return A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. + to_arrow_record_batch_stream_reader = function() { + ptr = self$internal_table_handle$get_arrow_array_stream_ptr() + rbsr = RecordBatchStreamReader$import_from_c(ptr) + return(rbsr) + }, + + #' @description + #' Imports the table referenced by this TableHandle into an Arrow Table. + #' @return A Table containing the data from the table referenced by this TableHandle. + to_arrow_table = function() { + rbsr = self$to_arrow_record_batch_stream_reader() + arrow_tbl = rbsr$read_table() + return(arrow_tbl) + }, + + #' @description + #' Imports the table referenced by this TableHandle into a dplyr Tibble. + #' @return A Tibble containing the data from the table referenced by this TableHandle. + to_tibble = function() { + rbsr = self$to_arrow_record_batch_stream_reader() + arrow_tbl = rbsr$read_table() + return(as_tibble(arrow_tbl)) + }, + + #' @description + #' Imports the table referenced by this TableHandle into an R Data Frame. + #' @return A Data Frame containing the data from the table referenced by this TableHandle. + to_data_frame = function() { + arrow_tbl = self$to_arrow_table() + return(as.data.frame(as.data.frame(arrow_tbl))) # TODO: for some reason as.data.frame on arrow table returns a tibble, not a data frame + }, + + ###################### TABLE OPERATIONS ####################### + # FILTERING OPERATIONS #' @description @@ -336,67 +399,6 @@ TableHandle <- R6Class("TableHandle", #TODO: merge = function(key_column, sources) { # return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) #}, - - #' @description - #' Whether the table referenced by this TableHandle is static or not. - #' @return TRUE if the table is static, or FALSE if the table is ticking. - is_static = function() { - return(private$is_static_field) - }, - - #' @description - #' Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. - #' @return The number of rows in the table. - nrow = function() { - if(!private$is_static_field) { - stop("The number of rows is not yet supported for dynamic tables.") - } - return(self$internal_table_handle$num_rows()) - }, - - #' @description - #' Binds the table referenced by this TableHandle to a variable on the server, - #' enabling it to be accessed by that name from any Deephaven API. - #' @param name Name for this table on the server. - bind_to_variable = function(name) { - .verify_string("name", name) - self$internal_table_handle$bind_to_variable(name) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. - #' @return A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. - to_arrow_record_batch_stream_reader = function() { - ptr = self$internal_table_handle$get_arrow_array_stream_ptr() - rbsr = RecordBatchStreamReader$import_from_c(ptr) - return(rbsr) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an Arrow Table. - #' @return A Table containing the data from the table referenced by this TableHandle. - to_arrow_table = function() { - rbsr = self$to_arrow_record_batch_stream_reader() - arrow_tbl = rbsr$read_table() - return(arrow_tbl) - }, - - #' @description - #' Imports the table referenced by this TableHandle into a dplyr Tibble. - #' @return A Tibble containing the data from the table referenced by this TableHandle. - to_tibble = function() { - rbsr = self$to_arrow_record_batch_stream_reader() - arrow_tbl = rbsr$read_table() - return(as_tibble(arrow_tbl)) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an R Data Frame. - #' @return A Data Frame containing the data from the table referenced by this TableHandle. - to_data_frame = function() { - arrow_tbl = self$to_arrow_table() - return(as.data.frame(as.data.frame(arrow_tbl))) # TODO: for some reason as.data.frame on arrow table returns a tibble, not a data frame - }, internal_table_handle = NULL ), diff --git a/R/rdeephaven/man/ClientOptions.Rd b/R/rdeephaven/man/ClientOptions.Rd index 06d85d6cefc..2e49dec7cb3 100644 --- a/R/rdeephaven/man/ClientOptions.Rd +++ b/R/rdeephaven/man/ClientOptions.Rd @@ -136,7 +136,8 @@ Use the TLS protocol in authentication and subsequent communication. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{root_certs}}{Optional PEM-encoded certificate root for server connections. Defaults to system defaults.} +\item{\code{root_certs}}{Optional PEM-encoded certificate root for server connections. Defaults to system defaults. +Adds an int-valued option for the configuration of the underlying gRPC channels.} } \if{html}{\out{
}} } @@ -149,6 +150,15 @@ Use the TLS protocol in authentication and subsequent communication. \if{html}{\out{
}}\preformatted{ClientOptions$add_int_option(opt, val)}\if{html}{\out{
}} } +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{opt}}{The option key.} + +\item{\code{val}}{The option value.} +} +\if{html}{\out{
}} +} } \if{html}{\out{
}} \if{html}{\out{}} diff --git a/R/rdeephaven/man/TableHandle.Rd b/R/rdeephaven/man/TableHandle.Rd index c2bc107af0c..1757e0033e1 100644 --- a/R/rdeephaven/man/TableHandle.Rd +++ b/R/rdeephaven/man/TableHandle.Rd @@ -32,6 +32,34 @@ new_table_handle2$bind_to_variable("new_table") \subsection{Public methods}{ \itemize{ \item \href{#method-TableHandle-new}{\code{TableHandle$new()}} +\item \href{#method-TableHandle-select}{\code{TableHandle$select()}} +\item \href{#method-TableHandle-view}{\code{TableHandle$view()}} +\item \href{#method-TableHandle-drop_columns}{\code{TableHandle$drop_columns()}} +\item \href{#method-TableHandle-update}{\code{TableHandle$update()}} +\item \href{#method-TableHandle-update_view}{\code{TableHandle$update_view()}} +\item \href{#method-TableHandle-where}{\code{TableHandle$where()}} +\item \href{#method-TableHandle-by}{\code{TableHandle$by()}} +\item \href{#method-TableHandle-min_by}{\code{TableHandle$min_by()}} +\item \href{#method-TableHandle-max_by}{\code{TableHandle$max_by()}} +\item \href{#method-TableHandle-sum_by}{\code{TableHandle$sum_by()}} +\item \href{#method-TableHandle-abs_sum_by}{\code{TableHandle$abs_sum_by()}} +\item \href{#method-TableHandle-var_by}{\code{TableHandle$var_by()}} +\item \href{#method-TableHandle-std_by}{\code{TableHandle$std_by()}} +\item \href{#method-TableHandle-avg_by}{\code{TableHandle$avg_by()}} +\item \href{#method-TableHandle-first_by}{\code{TableHandle$first_by()}} +\item \href{#method-TableHandle-last_by}{\code{TableHandle$last_by()}} +\item \href{#method-TableHandle-median_by}{\code{TableHandle$median_by()}} +\item \href{#method-TableHandle-percentile_by}{\code{TableHandle$percentile_by()}} +\item \href{#method-TableHandle-count_by}{\code{TableHandle$count_by()}} +\item \href{#method-TableHandle-w_avg_by}{\code{TableHandle$w_avg_by()}} +\item \href{#method-TableHandle-tail_by}{\code{TableHandle$tail_by()}} +\item \href{#method-TableHandle-head_by}{\code{TableHandle$head_by()}} +\item \href{#method-TableHandle-cross_join}{\code{TableHandle$cross_join()}} +\item \href{#method-TableHandle-natural_join}{\code{TableHandle$natural_join()}} +\item \href{#method-TableHandle-exact_join}{\code{TableHandle$exact_join()}} +\item \href{#method-TableHandle-head}{\code{TableHandle$head()}} +\item \href{#method-TableHandle-tail}{\code{TableHandle$tail()}} +\item \href{#method-TableHandle-ungroup}{\code{TableHandle$ungroup()}} \item \href{#method-TableHandle-is_static}{\code{TableHandle$is_static()}} \item \href{#method-TableHandle-nrow}{\code{TableHandle$nrow()}} \item \href{#method-TableHandle-bind_to_variable}{\code{TableHandle$bind_to_variable()}} @@ -50,18 +78,646 @@ new_table_handle2$bind_to_variable("new_table") \if{html}{\out{
}}\preformatted{TableHandle$new(table_handle)}\if{html}{\out{
}} } +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-select}{}}} +\subsection{Method \code{select()}}{ +Select columns from a table. The columns can be column names or formulas like +"NewCol = A + 12". See the Deephaven documentation for the difference between "select" and "view". +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$select(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{The columns to select.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-view}{}}} +\subsection{Method \code{view()}}{ +View columns from a table. The columns can be column names or formulas like +"NewCol = A + 12". See the Deephaven documentation for the difference between select() and view(). +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$view(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{The columns to view.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-drop_columns}{}}} +\subsection{Method \code{drop_columns()}}{ +Creates a new table from this table where the specified columns have been excluded. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$drop_columns(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{The columns to exclude.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-update}{}}} +\subsection{Method \code{update()}}{ +Creates a new table from this table, but including the additional specified columns. +See the Deephaven documentation for the difference between update() and updateView(). +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$update(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{The columns to add. For example, {"X = A + 5", "Y = X * 2"}.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-update_view}{}}} +\subsection{Method \code{update_view()}}{ +Creates a new view from this table, but including the additional specified columns. +See the Deephaven documentation for the difference between update() and updateView(). +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$update_view(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{The columns to add. For example, {"X = A + 5", "Y = X * 2"}.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-where}{}}} +\subsection{Method \code{where()}}{ +Creates a new table from this table, filtered by condition. Consult the Deephaven +documentation for more information about valid conditions. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$where(condition)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{condition}}{A Deephaven boolean expression such as "Price > 100" or "Col3 == Col1 * Col2".} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-by}{}}} +\subsection{Method \code{by()}}{ +Creates a new table from this table, grouped by columns with the column content grouped +into arrays. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-min_by}{}}} +\subsection{Method \code{min_by()}}{ +Creates a new table from this table, grouped by columns, with the "min" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$min_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-max_by}{}}} +\subsection{Method \code{max_by()}}{ +Creates a new table from this table, grouped by columns, with the "max" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$max_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-sum_by}{}}} +\subsection{Method \code{sum_by()}}{ +Creates a new table from this table, grouped by columns, with the "sum" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$sum_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-abs_sum_by}{}}} +\subsection{Method \code{abs_sum_by()}}{ +Creates a new table from this table, grouped by columns, with the "absSum" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$abs_sum_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-var_by}{}}} +\subsection{Method \code{var_by()}}{ +Creates a new table from this table, grouped by columns, with the "var" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$var_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-std_by}{}}} +\subsection{Method \code{std_by()}}{ +Creates a new table from this table, grouped by columns, with the "std" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$std_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-avg_by}{}}} +\subsection{Method \code{avg_by()}}{ +Creates a new table from this table, grouped by columns, with the "avg" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$avg_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-first_by}{}}} +\subsection{Method \code{first_by()}}{ +Creates a new table from this table, grouped by columns, with the "first" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$first_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-last_by}{}}} +\subsection{Method \code{last_by()}}{ +Creates a new table from this table, grouped by columns, with the "last" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$last_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-median_by}{}}} +\subsection{Method \code{median_by()}}{ +Creates a new table from this table, grouped by columns, with the "median" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$median_by(columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-percentile_by}{}}} +\subsection{Method \code{percentile_by()}}{ +Creates a new table from this table, grouped by columns, with the "percentile" aggregate operation +applied to the remaining columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$percentile_by(percentile, columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{percentile}}{The designated percentile} + +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-count_by}{}}} +\subsection{Method \code{count_by()}}{ +Creates a new table from this table, grouped by columns, having a new column named by +`countByColumn` containing the size of each group. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$count_by(count_by_column, columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{count_by_column}}{Name of the output column.} + +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-w_avg_by}{}}} +\subsection{Method \code{w_avg_by()}}{ +Creates a new table from this table, grouped by columns, having a new column named by +`weightColumn` containing the weighted average of each group. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$w_avg_by(weight_column, columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{weight_column}}{Name of the output column.} + +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-tail_by}{}}} +\subsection{Method \code{tail_by()}}{ +Creates a new table from this table, grouped by columns, containing the last `n` rows of +each group. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$tail_by(n, columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{n}}{Number of rows} + +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-head_by}{}}} +\subsection{Method \code{head_by()}}{ +Creates a new table from this table, grouped by columns, containing the first `n` rows of +each group. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$head_by(n, columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{n}}{Number of rows} + +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-cross_join}{}}} +\subsection{Method \code{cross_join()}}{ +Creates a new table by cross joining this table with `rightSide`. The tables are joined by +the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally +renamed by `columnsToAdd`. Example: +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$cross_join(right_side, columns_to_match, columns_to_add)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{right_side}}{The table to join with this table} + +\item{\code{columns_to_match}}{The columns to join on} + +\item{\code{columns_to_add}}{The columns from the right side to add, and possibly rename.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-natural_join}{}}} +\subsection{Method \code{natural_join()}}{ +Creates a new table by natural joining this table with `rightSide`. The tables are joined by +the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally +renamed by `columnsToAdd`. Example: +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$natural_join(right_side, columns_to_match, columns_to_add)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{right_side}}{The table to join with this table} + +\item{\code{columns_to_match}}{The columns to join on} + +\item{\code{columns_to_add}}{The columns from the right side to add, and possibly rename.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-exact_join}{}}} +\subsection{Method \code{exact_join()}}{ +Creates a new table by exact joining this table with `rightSide`. The tables are joined by +the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally +renamed by `columnsToAdd`. Example: +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$exact_join(right_side, columns_to_match, columns_to_add)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{right_side}}{The table to join with this table} + +\item{\code{columns_to_match}}{The columns to join on} + +\item{\code{columns_to_add}}{The columns from the right side to add, and possibly rename.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-head}{}}} +\subsection{Method \code{head()}}{ +Creates a new table from this table containing the first `n` rows of this table. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$head(n)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{n}}{Number of rows} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-tail}{}}} +\subsection{Method \code{tail()}}{ +Creates a new table from this table containing the last `n` rows of this table. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$tail(n)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{n}}{Number of rows} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-ungroup}{}}} +\subsection{Method \code{ungroup()}}{ +Creates a new table from this table with the column array data ungrouped. This is the inverse +of the by() const operation. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$ungroup(null_fill, group_by_columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{group_by_columns}}{Columns to ungroup.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-TableHandle-is_static}{}}} \subsection{Method \code{is_static()}}{ +Creates a new table from this table, sorted by sortPairs. + + +Creates a new table by merging `sources` together. The tables are essentially stacked on top +of each other. + + Whether the table referenced by this TableHandle is static or not. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{TableHandle$is_static()}\if{html}{\out{
}} } +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{sort_pairs}}{A vector of SortPair objects describing the sort. Each SortPair refers to +a column, a sort direction, and whether the sort should consider to the value's regular or +absolute value when doing comparisons.} + +\item{\code{sources}}{The tables to merge.} +} +\if{html}{\out{
}} +} \subsection{Returns}{ -TRUE if the table is static, or FALSE if the table is ticking. +A TableHandle referencing the new table. } } \if{html}{\out{
}} From 6d02151314a18ef8130d3c8f412bf9fb40a94e56 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 18 Jul 2023 10:11:53 -0500 Subject: [PATCH 07/73] Continue API expansion, do not expose all package functions to user --- R/rdeephaven/R/aggregate_functions.R | 64 +++++ R/rdeephaven/R/client_options_wrapper.R | 2 +- R/rdeephaven/R/client_wrapper.R | 2 +- R/rdeephaven/R/table_handle_wrapper.R | 49 ++-- R/rdeephaven/man/TableHandle.Rd | 320 +++++++++++------------- R/rdeephaven/src/client.cpp | 186 ++++++++++---- 6 files changed, 385 insertions(+), 238 deletions(-) create mode 100644 R/rdeephaven/R/aggregate_functions.R diff --git a/R/rdeephaven/R/aggregate_functions.R b/R/rdeephaven/R/aggregate_functions.R new file mode 100644 index 00000000000..55d0c6a20d0 --- /dev/null +++ b/R/rdeephaven/R/aggregate_functions.R @@ -0,0 +1,64 @@ +#' @export +agg.min = function(columns) { + return(INTERNAL_min(columns)) +} + +#' @export +agg.max = function(columns) { + return(INTERNAL_max(columns)) +} + +#' @export +agg.sum = function(columns) { + return(INTERNAL_sum(columns)) +} + +#' @export +agg.abs_sum = function(columns) { + return(INTERNAL_abs_sum(columns)) +} + +#' @export +agg.avg = function(columns) { + return(INTERNAL_avg(columns)) +} + +#' @export +agg.w_avg = function(weight_column, columns) { + return(INTERNAL_w_avg(weight_column, columns)) +} + +#' @export +agg.var = function(columns) { + return(INTERNAL_var(columns)) +} + +#' @export +agg.std = function(columns) { + return(INTERNAL_std(columns)) +} + +#' @export +agg.first = function(columns) { + return(INTERNAL_first(columns)) +} + +#' @export +agg.last = function(columns) { + return(INTERNAL_last(columns)) +} + +#' @export +agg.median = function(columns) { + return(INTERNAL_median(columns)) +} + +#' @export +agg.percentile = function(percentile, columns) { + return(INTERNAL_percentile(percentile, columns)) +} + +#' @export +agg.count = function(count_column) { + return(INTERNAL_count(count_column)) +} diff --git a/R/rdeephaven/R/client_options_wrapper.R b/R/rdeephaven/R/client_options_wrapper.R index 9b4408501e0..e4a02d939c1 100644 --- a/R/rdeephaven/R/client_options_wrapper.R +++ b/R/rdeephaven/R/client_options_wrapper.R @@ -32,7 +32,7 @@ #' client_options$set_session_type("groovy") #' client <- Client$new(target="url/to/secure/server", client_options=client_options) - +#' @export ClientOptions <- R6Class("ClientOptions", public = list( diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index c1933e1ffef..e535404d8ae 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -22,7 +22,7 @@ #' # run a python script on the server (default client options specify a Python console) #' client$run_script("print([i for i in range(10)])") - +#' @export Client <- R6Class("Client", public = list( diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 9c157447b13..6fb783ecca7 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -26,6 +26,7 @@ #' new_table_handle2 <- client$import_table(new_data_frame) #' new_table_handle2$bind_to_variable("new_table") +#' @export TableHandle <- R6Class("TableHandle", public = list( @@ -205,30 +206,40 @@ TableHandle <- R6Class("TableHandle", }, #' @description - #' Creates a new table from this table, grouped by columns, with the "var" aggregate operation + #' Creates a new table from this table, grouped by columns, with the "avg" aggregate operation #' applied to the remaining columns. #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. - var_by = function(columns) { - return(TableHandle$new(self$internal_table_handle$var_by(columns))) + avg_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$avg_by(columns))) }, #' @description - #' Creates a new table from this table, grouped by columns, with the "std" aggregate operation + #' Creates a new table from this table, grouped by columns, having a new column named by + #' `weightColumn` containing the weighted average of each group. + #' @param weight_column Name of the output column. + #' @param columns Columns to group by. + #' @return A TableHandle referencing the new table. + w_avg_by = function(weight_column, columns) { + return(TableHandle$new(self$internal_table_handle$w_avg_by(weight_column, columns))) + }, + + #' @description + #' Creates a new table from this table, grouped by columns, with the "var" aggregate operation #' applied to the remaining columns. #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. - std_by = function(columns) { - return(TableHandle$new(self$internal_table_handle$std_by(columns))) + var_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$var_by(columns))) }, #' @description - #' Creates a new table from this table, grouped by columns, with the "avg" aggregate operation + #' Creates a new table from this table, grouped by columns, with the "std" aggregate operation #' applied to the remaining columns. #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. - avg_by = function(columns) { - return(TableHandle$new(self$internal_table_handle$avg_by(columns))) + std_by = function(columns) { + return(TableHandle$new(self$internal_table_handle$std_by(columns))) }, #' @description @@ -279,13 +290,13 @@ TableHandle <- R6Class("TableHandle", }, #' @description - #' Creates a new table from this table, grouped by columns, having a new column named by - #' `weightColumn` containing the weighted average of each group. - #' @param weight_column Name of the output column. + #' Creates a new table from this table, grouped by columns, containing the first `n` rows of + #' each group. + #' @param n Number of rows #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. - w_avg_by = function(weight_column, columns) { - return(TableHandle$new(self$internal_table_handle$w_avg_by(weight_column, columns))) + head_by = function(n, columns) { + return(TableHandle$new(self$internal_table_handle$head_by(n, columns))) }, #' @description @@ -298,16 +309,6 @@ TableHandle <- R6Class("TableHandle", return(TableHandle$new(self$internal_table_handle$tail_by(n, columns))) }, - #' @description - #' Creates a new table from this table, grouped by columns, containing the first `n` rows of - #' each group. - #' @param n Number of rows - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - head_by = function(n, columns) { - return(TableHandle$new(self$internal_table_handle$head_by(n, columns))) - }, - # JOIN OPERATIONS #' @description diff --git a/R/rdeephaven/man/TableHandle.Rd b/R/rdeephaven/man/TableHandle.Rd index 1757e0033e1..5e6bdaff918 100644 --- a/R/rdeephaven/man/TableHandle.Rd +++ b/R/rdeephaven/man/TableHandle.Rd @@ -32,6 +32,13 @@ new_table_handle2$bind_to_variable("new_table") \subsection{Public methods}{ \itemize{ \item \href{#method-TableHandle-new}{\code{TableHandle$new()}} +\item \href{#method-TableHandle-is_static}{\code{TableHandle$is_static()}} +\item \href{#method-TableHandle-nrow}{\code{TableHandle$nrow()}} +\item \href{#method-TableHandle-bind_to_variable}{\code{TableHandle$bind_to_variable()}} +\item \href{#method-TableHandle-to_arrow_record_batch_stream_reader}{\code{TableHandle$to_arrow_record_batch_stream_reader()}} +\item \href{#method-TableHandle-to_arrow_table}{\code{TableHandle$to_arrow_table()}} +\item \href{#method-TableHandle-to_tibble}{\code{TableHandle$to_tibble()}} +\item \href{#method-TableHandle-to_data_frame}{\code{TableHandle$to_data_frame()}} \item \href{#method-TableHandle-select}{\code{TableHandle$select()}} \item \href{#method-TableHandle-view}{\code{TableHandle$view()}} \item \href{#method-TableHandle-drop_columns}{\code{TableHandle$drop_columns()}} @@ -43,30 +50,23 @@ new_table_handle2$bind_to_variable("new_table") \item \href{#method-TableHandle-max_by}{\code{TableHandle$max_by()}} \item \href{#method-TableHandle-sum_by}{\code{TableHandle$sum_by()}} \item \href{#method-TableHandle-abs_sum_by}{\code{TableHandle$abs_sum_by()}} +\item \href{#method-TableHandle-avg_by}{\code{TableHandle$avg_by()}} +\item \href{#method-TableHandle-w_avg_by}{\code{TableHandle$w_avg_by()}} \item \href{#method-TableHandle-var_by}{\code{TableHandle$var_by()}} \item \href{#method-TableHandle-std_by}{\code{TableHandle$std_by()}} -\item \href{#method-TableHandle-avg_by}{\code{TableHandle$avg_by()}} \item \href{#method-TableHandle-first_by}{\code{TableHandle$first_by()}} \item \href{#method-TableHandle-last_by}{\code{TableHandle$last_by()}} \item \href{#method-TableHandle-median_by}{\code{TableHandle$median_by()}} \item \href{#method-TableHandle-percentile_by}{\code{TableHandle$percentile_by()}} \item \href{#method-TableHandle-count_by}{\code{TableHandle$count_by()}} -\item \href{#method-TableHandle-w_avg_by}{\code{TableHandle$w_avg_by()}} -\item \href{#method-TableHandle-tail_by}{\code{TableHandle$tail_by()}} \item \href{#method-TableHandle-head_by}{\code{TableHandle$head_by()}} +\item \href{#method-TableHandle-tail_by}{\code{TableHandle$tail_by()}} \item \href{#method-TableHandle-cross_join}{\code{TableHandle$cross_join()}} \item \href{#method-TableHandle-natural_join}{\code{TableHandle$natural_join()}} \item \href{#method-TableHandle-exact_join}{\code{TableHandle$exact_join()}} \item \href{#method-TableHandle-head}{\code{TableHandle$head()}} \item \href{#method-TableHandle-tail}{\code{TableHandle$tail()}} \item \href{#method-TableHandle-ungroup}{\code{TableHandle$ungroup()}} -\item \href{#method-TableHandle-is_static}{\code{TableHandle$is_static()}} -\item \href{#method-TableHandle-nrow}{\code{TableHandle$nrow()}} -\item \href{#method-TableHandle-bind_to_variable}{\code{TableHandle$bind_to_variable()}} -\item \href{#method-TableHandle-to_arrow_record_batch_stream_reader}{\code{TableHandle$to_arrow_record_batch_stream_reader()}} -\item \href{#method-TableHandle-to_arrow_table}{\code{TableHandle$to_arrow_table()}} -\item \href{#method-TableHandle-to_tibble}{\code{TableHandle$to_tibble()}} -\item \href{#method-TableHandle-to_data_frame}{\code{TableHandle$to_data_frame()}} \item \href{#method-TableHandle-clone}{\code{TableHandle$clone()}} } } @@ -78,6 +78,102 @@ new_table_handle2$bind_to_variable("new_table") \if{html}{\out{
}}\preformatted{TableHandle$new(table_handle)}\if{html}{\out{
}} } +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-is_static}{}}} +\subsection{Method \code{is_static()}}{ +Whether the table referenced by this TableHandle is static or not. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$is_static()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +TRUE if the table is static, or FALSE if the table is ticking. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-nrow}{}}} +\subsection{Method \code{nrow()}}{ +Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$nrow()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +The number of rows in the table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-bind_to_variable}{}}} +\subsection{Method \code{bind_to_variable()}}{ +Binds the table referenced by this TableHandle to a variable on the server, +enabling it to be accessed by that name from any Deephaven API. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$bind_to_variable(name)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{name}}{Name for this table on the server.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-to_arrow_record_batch_stream_reader}{}}} +\subsection{Method \code{to_arrow_record_batch_stream_reader()}}{ +Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$to_arrow_record_batch_stream_reader()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-to_arrow_table}{}}} +\subsection{Method \code{to_arrow_table()}}{ +Imports the table referenced by this TableHandle into an Arrow Table. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$to_arrow_table()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +A Table containing the data from the table referenced by this TableHandle. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-to_tibble}{}}} +\subsection{Method \code{to_tibble()}}{ +Imports the table referenced by this TableHandle into a dplyr Tibble. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$to_tibble()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +A Tibble containing the data from the table referenced by this TableHandle. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-to_data_frame}{}}} +\subsection{Method \code{to_data_frame()}}{ +Imports the table referenced by this TableHandle into an R Data Frame. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$to_data_frame()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +A Data Frame containing the data from the table referenced by this TableHandle. +} } \if{html}{\out{
}} \if{html}{\out{}} @@ -310,13 +406,13 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-var_by}{}}} -\subsection{Method \code{var_by()}}{ -Creates a new table from this table, grouped by columns, with the "var" aggregate operation +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-avg_by}{}}} +\subsection{Method \code{avg_by()}}{ +Creates a new table from this table, grouped by columns, with the "avg" aggregate operation applied to the remaining columns. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$var_by(columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$avg_by(columns)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -331,13 +427,36 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-std_by}{}}} -\subsection{Method \code{std_by()}}{ -Creates a new table from this table, grouped by columns, with the "std" aggregate operation +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-w_avg_by}{}}} +\subsection{Method \code{w_avg_by()}}{ +Creates a new table from this table, grouped by columns, having a new column named by +`weightColumn` containing the weighted average of each group. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$w_avg_by(weight_column, columns)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{weight_column}}{Name of the output column.} + +\item{\code{columns}}{Columns to group by.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-var_by}{}}} +\subsection{Method \code{var_by()}}{ +Creates a new table from this table, grouped by columns, with the "var" aggregate operation applied to the remaining columns. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$std_by(columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$var_by(columns)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -352,13 +471,13 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-avg_by}{}}} -\subsection{Method \code{avg_by()}}{ -Creates a new table from this table, grouped by columns, with the "avg" aggregate operation +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-std_by}{}}} +\subsection{Method \code{std_by()}}{ +Creates a new table from this table, grouped by columns, with the "std" aggregate operation applied to the remaining columns. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$avg_by(columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$std_by(columns)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -482,19 +601,19 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-w_avg_by}{}}} -\subsection{Method \code{w_avg_by()}}{ -Creates a new table from this table, grouped by columns, having a new column named by -`weightColumn` containing the weighted average of each group. +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-head_by}{}}} +\subsection{Method \code{head_by()}}{ +Creates a new table from this table, grouped by columns, containing the first `n` rows of +each group. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$w_avg_by(weight_column, columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$head_by(n, columns)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{weight_column}}{Name of the output column.} +\item{\code{n}}{Number of rows} \item{\code{columns}}{Columns to group by.} } @@ -519,29 +638,6 @@ each group. \describe{ \item{\code{n}}{Number of rows} -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-head_by}{}}} -\subsection{Method \code{head_by()}}{ -Creates a new table from this table, grouped by columns, containing the first `n` rows of -each group. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$head_by(n, columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{n}}{Number of rows} - \item{\code{columns}}{Columns to group by.} } \if{html}{\out{
}} @@ -690,120 +786,6 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-is_static}{}}} -\subsection{Method \code{is_static()}}{ -Creates a new table from this table, sorted by sortPairs. - - -Creates a new table by merging `sources` together. The tables are essentially stacked on top -of each other. - - -Whether the table referenced by this TableHandle is static or not. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$is_static()}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{sort_pairs}}{A vector of SortPair objects describing the sort. Each SortPair refers to -a column, a sort direction, and whether the sort should consider to the value's regular or -absolute value when doing comparisons.} - -\item{\code{sources}}{The tables to merge.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-nrow}{}}} -\subsection{Method \code{nrow()}}{ -Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$nrow()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -The number of rows in the table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-bind_to_variable}{}}} -\subsection{Method \code{bind_to_variable()}}{ -Binds the table referenced by this TableHandle to a variable on the server, -enabling it to be accessed by that name from any Deephaven API. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$bind_to_variable(name)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{name}}{Name for this table on the server.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_arrow_record_batch_stream_reader}{}}} -\subsection{Method \code{to_arrow_record_batch_stream_reader()}}{ -Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_arrow_record_batch_stream_reader()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_arrow_table}{}}} -\subsection{Method \code{to_arrow_table()}}{ -Imports the table referenced by this TableHandle into an Arrow Table. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_arrow_table()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A Table containing the data from the table referenced by this TableHandle. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_tibble}{}}} -\subsection{Method \code{to_tibble()}}{ -Imports the table referenced by this TableHandle into a dplyr Tibble. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_tibble()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A Tibble containing the data from the table referenced by this TableHandle. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_data_frame}{}}} -\subsection{Method \code{to_data_frame()}}{ -Imports the table referenced by this TableHandle into an R Data Frame. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_data_frame()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A Data Frame containing the data from the table referenced by this TableHandle. -} -} -\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-TableHandle-clone}{}}} \subsection{Method \code{clone()}}{ diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 19e56823660..3ef63c177be 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -14,23 +14,81 @@ #include // forward declaration of classes +class AggregateWrapper; +class TableHandleWrapper; class ClientOptionsWrapper; class ClientWrapper; // ######################### DH WRAPPERS ######################### -class TableHandleWrapper { +class AggregateWrapper { public: - TableHandleWrapper(deephaven::client::TableHandle ref_table) : internal_tbl_hdl(std::move(ref_table)) {}; + AggregateWrapper(deephaven::client::Aggregate aggregate) : + internal_aggregate(std::move(aggregate)) {} +private: + deephaven::client::Aggregate internal_aggregate; + friend TableHandleWrapper; +}; - // HELPER FUNCTIONS +AggregateWrapper* INTERNAL_min(std::vector columnSpecs) { + //AggregateWrapper* agg_wrap_ptr = new AggregateWrapper(deephaven::client::Aggregate::min(columnSpecs)); + //return Rcpp::XPtr(agg_wrap_ptr, true); + return new AggregateWrapper(deephaven::client::Aggregate::min(columnSpecs)); +} - std::vector convertTableHandleWrapperVector(std::vector input) { - std::vector output(input.size()); - std::transform(input.begin(), input.end(), - output.begin(), [](const TableHandleWrapper& wrapper) { return wrapper.internal_tbl_hdl; }); - return output; - }; +AggregateWrapper* INTERNAL_max(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::max(columnSpecs)); +} + +AggregateWrapper* INTERNAL_sum(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::sum(columnSpecs)); +} + +AggregateWrapper* INTERNAL_absSum(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::absSum(columnSpecs)); +} + +AggregateWrapper* INTERNAL_avg(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::avg(columnSpecs)); +} + +AggregateWrapper* INTERNAL_wAvg(std::string weightColumn, std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::wavg(weightColumn, columnSpecs)); +} + +AggregateWrapper* INTERNAL_var(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::var(columnSpecs)); +} + +AggregateWrapper* INTERNAL_std(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::std(columnSpecs)); +} + +AggregateWrapper* INTERNAL_first(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::first(columnSpecs)); +} + +AggregateWrapper* INTERNAL_last(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::last(columnSpecs)); +} + +AggregateWrapper* INTERNAL_median(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::med(columnSpecs)); +} + +AggregateWrapper* INTERNAL_percentile(double percentile, std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::pct(percentile, false, columnSpecs)); +} + +AggregateWrapper* INTERNAL_count(std::string columnSpec) { + return new AggregateWrapper(deephaven::client::Aggregate::count(columnSpec)); +} + + +class TableHandleWrapper { +public: + TableHandleWrapper(deephaven::client::TableHandle ref_table) : + internal_tbl_hdl(std::move(ref_table)) {}; // TABLE OPERATIONS @@ -62,6 +120,16 @@ class TableHandleWrapper { // AGGREGATION OPERATIONS + TableHandleWrapper* aggBy(std::vector aggregations) { + std::vector converted_aggregations; + converted_aggregations.reserve(aggregations.size()); + + for (int i = 0; i < aggregations.size(); i++) { + converted_aggregations.push_back(aggregations[i].internal_aggregate); + } + return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations))); + } + TableHandleWrapper* by(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.by(columnSpecs)); }; @@ -82,6 +150,14 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.absSumBy(columnSpecs)); }; + TableHandleWrapper* avgBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.avgBy(columnSpecs)); + }; + + TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.wAvgBy(weightColumn, columnSpecs)); + }; + TableHandleWrapper* varBy(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.varBy(columnSpecs)); }; @@ -90,10 +166,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.stdBy(columnSpecs)); }; - TableHandleWrapper* avgBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.avgBy(columnSpecs)); - }; - TableHandleWrapper* firstBy(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.firstBy(columnSpecs)); }; @@ -114,18 +186,14 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.countBy(countByColumn, columnSpecs)); }; - TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.wAvgBy(weightColumn, columnSpecs)); + TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); }; TableHandleWrapper* tailBy(int64_t n, std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.tailBy(n, columnSpecs)); }; - TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); - }; - // JOIN OPERATIONS TableHandleWrapper* crossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { @@ -213,9 +281,8 @@ class TableHandleWrapper { class ClientOptionsWrapper { public: - ClientOptionsWrapper() { - internal_options = new deephaven::client::ClientOptions(); - } + ClientOptionsWrapper() : + internal_options(std::make_shared()) {} void setDefaultAuthentication() { internal_options->setDefaultAuthentication(); @@ -254,16 +321,17 @@ class ClientOptionsWrapper { } private: - - deephaven::client::ClientOptions* internal_options; - friend ClientWrapper* newClientWrapper(const std::string &target, const ClientOptionsWrapper &client_options); + std::shared_ptr internal_options; + friend ClientWrapper; }; - class ClientWrapper { public: + ClientWrapper(std::string target, const ClientOptionsWrapper &client_options) : + internal_client(deephaven::client::Client::connect(target, *client_options.internal_options)) {} + /** * Fetches a reference to a table named tableName on the server if it exists. * @param tableName Name of the table to search for. @@ -352,26 +420,23 @@ class ClientWrapper { } private: - ClientWrapper(deephaven::client::Client ref) : internal_client(std::move(ref)) {}; - const deephaven::client::Client internal_client; const deephaven::client::TableHandleManager internal_tbl_hdl_mngr = internal_client.getManager(); - - friend ClientWrapper* newClientWrapper(const std::string &target, const ClientOptionsWrapper &client_options); }; -// factory method for calling private constructor, Rcpp does not like in constructor -// the current implementation of passing authentication args to C++ client is terrible and needs to be redone. Only this could make Rcpp happy in a days work -/** - * Factory method for creating a new ClientWrapper, which is responsible for maintaining a connection to the client. - * @param target URL that the server is running on. - * @param client_options A ClientOptionsWrapper containing the server connection information. See deephaven::client::ClientOptions for more information. - */ -ClientWrapper* newClientWrapper(const std::string &target, const ClientOptionsWrapper &client_options) { - return new ClientWrapper(deephaven::client::Client::connect(target, *client_options.internal_options)); +class class1 { +public: + class1() = default; }; +class class2 { +public: + class2() = default; + void method(std::vector args) { + std::cout << "hello!" << std::endl; + } +}; // ######################### RCPP GLUE ######################### @@ -380,10 +445,26 @@ using namespace Rcpp; RCPP_EXPOSED_CLASS(ClientOptionsWrapper) RCPP_EXPOSED_CLASS(TableHandleWrapper) +RCPP_EXPOSED_CLASS(AggregateWrapper) RCPP_EXPOSED_CLASS(ArrowArrayStream) +RCPP_EXPOSED_CLASS(class1) +RCPP_EXPOSED_CLASS(class2) + RCPP_MODULE(DeephavenInternalModule) { + class_("TestClass1") + .constructor() + ; + + class_("TestClass2") + .constructor() + .method("method", &class2::method) + ; + + class_("INTERNAL_Aggregate") + ; + class_("INTERNAL_TableHandle") .method("select", &TableHandleWrapper::select) .method("view", &TableHandleWrapper::view) @@ -391,30 +472,35 @@ RCPP_MODULE(DeephavenInternalModule) { .method("update", &TableHandleWrapper::update) .method("update_view", &TableHandleWrapper::updateView) .method("where", &TableHandleWrapper::where) + + //.method("agg_by", &TableHandleWrapper::aggBy) .method("by", &TableHandleWrapper::by) .method("min_by", &TableHandleWrapper::minBy) .method("max_by", &TableHandleWrapper::maxBy) .method("sum_by", &TableHandleWrapper::sumBy) .method("abs_sum_by", &TableHandleWrapper::absSumBy) + .method("avg_by", &TableHandleWrapper::avgBy) + .method("w_avg_by", &TableHandleWrapper::wAvgBy) .method("var_by", &TableHandleWrapper::varBy) .method("std_by", &TableHandleWrapper::stdBy) - .method("avg_by", &TableHandleWrapper::avgBy) .method("first_by", &TableHandleWrapper::firstBy) .method("last_by", &TableHandleWrapper::lastBy) .method("median_by", &TableHandleWrapper::medianBy) .method("percentile_by", &TableHandleWrapper::percentileBy) .method("count_by", &TableHandleWrapper::countBy) - .method("w_avg_by", &TableHandleWrapper::wAvgBy) - .method("tail_by", &TableHandleWrapper::tailBy) .method("head_by", &TableHandleWrapper::headBy) + .method("tail_by", &TableHandleWrapper::tailBy) + .method("cross_join", &TableHandleWrapper::crossJoin) .method("natural_join", &TableHandleWrapper::naturalJoin) .method("exact_join", &TableHandleWrapper::exactJoin) + .method("head", &TableHandleWrapper::head) .method("tail", &TableHandleWrapper::tail) .method("ungroup", &TableHandleWrapper::ungroup) // TODO: .method("sort", &TableHandleWrapper::sort) // TODO: .method("merge", &TableHandleWrapper::merge) + .method("is_static", &TableHandleWrapper::isStatic) .method("num_rows", &TableHandleWrapper::numRows) .method("bind_to_variable", &TableHandleWrapper::bindToVariable) @@ -435,7 +521,7 @@ RCPP_MODULE(DeephavenInternalModule) { ; class_("INTERNAL_Client") - .factory(newClientWrapper) + .constructor() .method("open_table", &ClientWrapper::openTable) .method("empty_table", &ClientWrapper::emptyTable) .method("time_table", &ClientWrapper::timeTable) @@ -444,4 +530,18 @@ RCPP_MODULE(DeephavenInternalModule) { .method("new_arrow_array_stream_ptr", &ClientWrapper::newArrowArrayStreamPtr) .method("new_table_from_arrow_array_stream_ptr", &ClientWrapper::newTableFromArrowArrayStreamPtr) ; + + function("INTERNAL_min", &INTERNAL_min); + function("INTERNAL_max", &INTERNAL_max); + function("INTERNAL_sum", &INTERNAL_sum); + function("INTERNAL_abs_sum", &INTERNAL_absSum); + function("INTERNAL_avg", &INTERNAL_avg); + function("INTERNAL_w_avg", &INTERNAL_wAvg); + function("INTERNAL_var", &INTERNAL_var); + function("INTERNAL_std", &INTERNAL_std); + function("INTERNAL_first", &INTERNAL_first); + function("INTERNAL_last", &INTERNAL_last); + function("INTERNAL_median", &INTERNAL_median); + function("INTERNAL_percentile", &INTERNAL_percentile); + function("INTERNAL_count", &INTERNAL_count); } From 75ef045b0bc451073b01a6d5bed06ecb7fa6e5d9 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 18 Jul 2023 10:34:58 -0500 Subject: [PATCH 08/73] Get rid of experimenting that should not have been committed --- R/rdeephaven/src/client.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 3ef63c177be..537c2d6742d 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -425,20 +425,6 @@ class ClientWrapper { }; -class class1 { -public: - class1() = default; -}; - -class class2 { -public: - class2() = default; - void method(std::vector args) { - std::cout << "hello!" << std::endl; - } -}; - - // ######################### RCPP GLUE ######################### using namespace Rcpp; @@ -448,20 +434,8 @@ RCPP_EXPOSED_CLASS(TableHandleWrapper) RCPP_EXPOSED_CLASS(AggregateWrapper) RCPP_EXPOSED_CLASS(ArrowArrayStream) -RCPP_EXPOSED_CLASS(class1) -RCPP_EXPOSED_CLASS(class2) - RCPP_MODULE(DeephavenInternalModule) { - class_("TestClass1") - .constructor() - ; - - class_("TestClass2") - .constructor() - .method("method", &class2::method) - ; - class_("INTERNAL_Aggregate") ; From 86cb58ed6936d6e03946debca62e7023f1fea63b Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 19 Jul 2023 13:15:12 -0500 Subject: [PATCH 09/73] Clean up R wrapping, implement agg_by, configure NAMESPACE to only expose relevant functions via roxygen tags --- R/rdeephaven/NAMESPACE | 3 --- R/rdeephaven/R/aggregate_functions.R | 26 ++++++++++----------- R/rdeephaven/R/aggregate_wrapper.R | 18 ++++++++++++++ R/rdeephaven/R/client_options_wrapper.R | 24 +++++++++---------- R/rdeephaven/R/client_wrapper.R | 16 ++++++------- R/rdeephaven/R/helper_functions.R | 8 +++++-- R/rdeephaven/R/table_handle_wrapper.R | 31 ++++++++++++++++++------- R/rdeephaven/src/client.cpp | 27 ++++++++++++++------- 8 files changed, 98 insertions(+), 55 deletions(-) delete mode 100644 R/rdeephaven/NAMESPACE create mode 100644 R/rdeephaven/R/aggregate_wrapper.R diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE deleted file mode 100644 index 0a33cb56cd5..00000000000 --- a/R/rdeephaven/NAMESPACE +++ /dev/null @@ -1,3 +0,0 @@ -useDynLib(rdeephaven, .registration=TRUE) -importFrom(Rcpp, evalCpp) -exportPattern("^[[:alpha:]]+") \ No newline at end of file diff --git a/R/rdeephaven/R/aggregate_functions.R b/R/rdeephaven/R/aggregate_functions.R index 55d0c6a20d0..eeda887c933 100644 --- a/R/rdeephaven/R/aggregate_functions.R +++ b/R/rdeephaven/R/aggregate_functions.R @@ -1,64 +1,64 @@ #' @export agg.min = function(columns) { - return(INTERNAL_min(columns)) + return(Aggregation$new(INTERNAL_min(columns))) } #' @export agg.max = function(columns) { - return(INTERNAL_max(columns)) + return(Aggregation$new(INTERNAL_max(columns))) } #' @export agg.sum = function(columns) { - return(INTERNAL_sum(columns)) + return(Aggregation$new(INTERNAL_sum(columns))) } #' @export agg.abs_sum = function(columns) { - return(INTERNAL_abs_sum(columns)) + return(Aggregation$new(INTERNAL_abs_sum(columns))) } #' @export agg.avg = function(columns) { - return(INTERNAL_avg(columns)) + return(Aggregation$new(INTERNAL_avg(columns))) } #' @export agg.w_avg = function(weight_column, columns) { - return(INTERNAL_w_avg(weight_column, columns)) + return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) } #' @export agg.var = function(columns) { - return(INTERNAL_var(columns)) + return(Aggregation$new(INTERNAL_var(columns))) } #' @export agg.std = function(columns) { - return(INTERNAL_std(columns)) + return(Aggregation$new(INTERNAL_std(columns))) } #' @export agg.first = function(columns) { - return(INTERNAL_first(columns)) + return(Aggregation$new(INTERNAL_first(columns))) } #' @export agg.last = function(columns) { - return(INTERNAL_last(columns)) + return(Aggregation$new(INTERNAL_last(columns))) } #' @export agg.median = function(columns) { - return(INTERNAL_median(columns)) + return(Aggregation$new(INTERNAL_median(columns))) } #' @export agg.percentile = function(percentile, columns) { - return(INTERNAL_percentile(percentile, columns)) + return(Aggregation$new(INTERNAL_percentile(percentile, columns))) } #' @export agg.count = function(count_column) { - return(INTERNAL_count(count_column)) + return(Aggregation$new(INTERNAL_count(count_column))) } diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R new file mode 100644 index 00000000000..de92c33ae19 --- /dev/null +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -0,0 +1,18 @@ +#' @export +Aggregation <- R6Class("Aggregation", + public = list( + + #' @description + #' Create an Aggregation instance. + initialize = function(aggregation) { + if (class(aggregation) != "Rcpp_INTERNAL_Aggregate") { + stop("'aggregation' should be an internal Deephaven Aggregation. If you're seeing this, + you are trying to call the constructor of an Aggregation directly, which is not advised. + Please use one of the provided aggregation functions instead.") + } + self$internal_aggregation <- aggregation + }, + + internal_aggregation = NULL + ) +) \ No newline at end of file diff --git a/R/rdeephaven/R/client_options_wrapper.R b/R/rdeephaven/R/client_options_wrapper.R index e4a02d939c1..a4577fcc735 100644 --- a/R/rdeephaven/R/client_options_wrapper.R +++ b/R/rdeephaven/R/client_options_wrapper.R @@ -53,8 +53,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param username Username of the account to use for authentication, supplied as a string. #' @param password Password of the account, supplied as a string. set_basic_authentication = function(username, password) { - .verify_string("username", username) - .verify_string("password", password) + verify_string("username", username) + verify_string("password", password) self$internal_client_options$set_basic_authentication(username, password) }, @@ -63,8 +63,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param auth_key Key to use for authentication, supplied as a string. #' @param auth_value Value to use for authentication, supplied as a string. set_custom_authentication = function(auth_key, auth_value) { - .verify_string("auth_key", auth_key) - .verify_string("auth_value", auth_value) + verify_string("auth_key", auth_key) + verify_string("auth_value", auth_value) self$internal_client_options$set_custom_authentication(auth_key, auth_value) }, @@ -72,7 +72,7 @@ ClientOptions <- R6Class("ClientOptions", #' Set the session type of the console (e.g., "python", "groovy", etc.). The session type must be supported on the server. #' @param session_type Desired language of the console. "python", "groovy", etc. set_session_type = function(session_type) { - .verify_string("session_type", session_type) + verify_string("session_type", session_type) self$internal_client_options$set_session_type(session_type) }, @@ -80,7 +80,7 @@ ClientOptions <- R6Class("ClientOptions", #' Use the TLS protocol in authentication and subsequent communication. #' @param root_certs Optional PEM-encoded certificate root for server connections. Defaults to system defaults. use_tls = function(root_certs = "") { - .verify_string("root_certs", root_certs) + verify_string("root_certs", root_certs) self$internal_client_options$set_use_tls(TRUE) self$internal_client_options$set_tls_root_certs(root_certs) }, @@ -90,8 +90,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param opt The option key. #' @param val The option value. add_int_option = function(opt, val) { - .verify_string("opt", opt) - .verify_int("val", val) + verify_string("opt", opt) + verify_int("val", val) self$internal_client_options$add_int_option(opt, val) }, @@ -100,8 +100,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param opt The option key. #' @param val The option valiue. add_string_option = function(opt, val) { - .verify_string("opt", opt) - .verify_string("val", val) + verify_string("opt", opt) + verify_string("val", val) self$internal_client_options$add_string_option(opt, val) }, @@ -110,8 +110,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param header_name The header name #' @param header_value The header value add_extra_header = function(header_name, header_value) { - .verify_string("header_name", header_name) - .verify_string("header_value", header_value) + verify_string("header_name", header_name) + verify_string("header_value", header_value) self$internal_client_options$add_extra_header(header_name, header_value) }, diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index e535404d8ae..b2b16bb279f 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -32,9 +32,9 @@ Client <- R6Class("Client", #' @param client_options ClientOptions instance with the parameters needed to connect to the server. #' See ?ClientOptions for more information. initialize = function(target, client_options) { - .verify_string("target", target) - if (class(client_options)[[1]] != "ClientOptions") { - stop(paste("'client_options' should be a Deephaven ClientOptions object. Got an object of type", class(client_options)[[1]], "instead.")) + verify_string("target", target) + if (first_class(client_options) != "ClientOptions") { + stop(paste("'client_options' should be a Deephaven ClientOptions object. Got an object of type", first_class(client_options), "instead.")) } private$internal_client <- new(INTERNAL_Client, target=target, client_options=client_options$internal_client_options) @@ -45,7 +45,7 @@ Client <- R6Class("Client", #' @param name Name of the table to open from the server, passed as a string. #' @return TableHandle reference to the requested table. open_table = function(name) { - .verify_string("name", name) + verify_string("name", name) if (!private$check_for_table(name)) { stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) } @@ -83,14 +83,12 @@ Client <- R6Class("Client", #' Runs a script on the server. The script must be in the language that the server console was started with. #' @param script Code to be executed on the server, passed as a string. run_script = function(script) { - .verify_string("script", script) + verify_string("script", script) private$internal_client$run_script(script) } ), private = list( - internal_client = NULL, - check_for_table = function(name) { return(private$internal_client$check_for_table(name)) }, @@ -114,6 +112,8 @@ Client <- R6Class("Client", df_to_dh_table = function(data_frame) { arrow_tbl = arrow_table(data_frame) return(private$arrow_to_dh_table(arrow_tbl)) - } + }, + + internal_client = NULL ) ) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 95822211bb9..408c8fa9a41 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -1,4 +1,8 @@ -.verify_string <- function(arg_name, string_candidate) { +first_class = function(arg) { + return(class(arg)[[1]]) +} + +verify_string <- function(arg_name, string_candidate) { if (class(string_candidate)[[1]] != "character") { stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", class(string_candidate)[[1]], " instead.")) } else if (length(string_candidate) != 1) { @@ -6,7 +10,7 @@ } } -.verify_int <- function(arg_name, int_candidate) { +verify_int <- function(arg_name, int_candidate) { if (class(int_candidate)[[1]] != "numeric") { stop(paste0("'", arg_name, "' must be an integer. Got an object of class ", class(int_candidate)[[1]], " instead.")) } else if (all.equal(int_candidate, as.integer(int_candidate)) != TRUE) { diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 6fb783ecca7..f0b14570dc3 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -31,13 +31,12 @@ TableHandle <- R6Class("TableHandle", public = list( initialize = function(table_handle) { - if (class(table_handle)[[1]] != "Rcpp_INTERNAL_TableHandle") { + if (first_class(table_handle) != "Rcpp_INTERNAL_TableHandle") { stop("'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") } self$internal_table_handle <- table_handle private$is_static_field <- self$internal_table_handle$is_static() - print("initializing!") }, #' @description @@ -62,7 +61,7 @@ TableHandle <- R6Class("TableHandle", #' enabling it to be accessed by that name from any Deephaven API. #' @param name Name for this table on the server. bind_to_variable = function(name) { - .verify_string("name", name) + verify_string("name", name) self$internal_table_handle$bind_to_variable(name) }, @@ -161,12 +160,23 @@ TableHandle <- R6Class("TableHandle", # AGGREGATION OPERATIONS #' @description - #' Creates a new table from this table, grouped by columns with the column content grouped - #' into arrays. - #' @param columns Columns to group by. + #' Creates a new table from this table with one or more aggregations applied to the specified columns. + #' @param aggregations Deephaven Aggregations to apply to this table. #' @return A TableHandle referencing the new table. - by = function(columns) { - return(TableHandle$new(self$internal_table_handle$by(columns))) + agg_by = function(aggregations) { + + if ((first_class(aggregations) == "list") && (any(lapply(aggregations, first_class) != "Aggregation"))) { + stop("dumb!!") + } + else if ((first_class(aggregations) != "list") && (first_class(aggregations) != "Aggregation")) { + stop("dumber!!") + } + else if ((first_class(aggregations) != "list") && (first_class(aggregations) == "Aggregation")) { + aggregations = c(aggregations) + } + unwrapped_aggregations = lapply(aggregations, private$strip_r6_wrapping_from_aggregation) + + return(TableHandle$new(self$internal_table_handle$agg_by(unwrapped_aggregations))) }, #' @description @@ -404,6 +414,11 @@ TableHandle <- R6Class("TableHandle", internal_table_handle = NULL ), private = list( + + strip_r6_wrapping_from_aggregation = function(r6_aggregation) { + return(r6_aggregation$internal_aggregation) + }, + is_static_field = NULL ) ) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 537c2d6742d..567c4f19262 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -11,6 +11,13 @@ #include #include +//#include +//class AggregateWrapper; +//namespace Rcpp { +// template <> SEXP wrap(const std::vector&); +// template <> std::vector as(SEXP); +//} + #include // forward declaration of classes @@ -23,16 +30,16 @@ class ClientWrapper; class AggregateWrapper { public: + AggregateWrapper(); AggregateWrapper(deephaven::client::Aggregate aggregate) : - internal_aggregate(std::move(aggregate)) {} + internal_aggregation(std::move(aggregate)) { + } private: - deephaven::client::Aggregate internal_aggregate; + deephaven::client::Aggregate internal_aggregation; friend TableHandleWrapper; }; AggregateWrapper* INTERNAL_min(std::vector columnSpecs) { - //AggregateWrapper* agg_wrap_ptr = new AggregateWrapper(deephaven::client::Aggregate::min(columnSpecs)); - //return Rcpp::XPtr(agg_wrap_ptr, true); return new AggregateWrapper(deephaven::client::Aggregate::min(columnSpecs)); } @@ -120,12 +127,15 @@ class TableHandleWrapper { // AGGREGATION OPERATIONS - TableHandleWrapper* aggBy(std::vector aggregations) { + TableHandleWrapper* aggBy(Rcpp::List aggregations) { std::vector converted_aggregations; converted_aggregations.reserve(aggregations.size()); - for (int i = 0; i < aggregations.size(); i++) { - converted_aggregations.push_back(aggregations[i].internal_aggregate); + for(int i = 0; i < aggregations.size(); i++) { + Rcpp::Environment aggregation = aggregations[i]; + Rcpp::XPtr xptr(aggregation.get(".pointer")); + deephaven::client::Aggregate internal_aggregation = xptr->internal_aggregation; + converted_aggregations.push_back(internal_aggregation); } return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations))); } @@ -447,8 +457,7 @@ RCPP_MODULE(DeephavenInternalModule) { .method("update_view", &TableHandleWrapper::updateView) .method("where", &TableHandleWrapper::where) - //.method("agg_by", &TableHandleWrapper::aggBy) - .method("by", &TableHandleWrapper::by) + .method("agg_by", &TableHandleWrapper::aggBy) .method("min_by", &TableHandleWrapper::minBy) .method("max_by", &TableHandleWrapper::maxBy) .method("sum_by", &TableHandleWrapper::sumBy) From e7fcb8c6bb1b2450857567789411d3996d7a99af Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 19 Jul 2023 18:45:23 -0500 Subject: [PATCH 10/73] Refactor type conversion logic, R-level type checking, actually add NAMESPACE this time --- R/rdeephaven/NAMESPACE | 21 +++++++++ R/rdeephaven/R/aggregate_functions.R | 15 +++++++ R/rdeephaven/R/helper_functions.R | 20 ++++++--- R/rdeephaven/R/table_handle_wrapper.R | 46 ++++++++++++++++--- R/rdeephaven/src/client.cpp | 63 ++++++++++++++++++--------- 5 files changed, 131 insertions(+), 34 deletions(-) create mode 100644 R/rdeephaven/NAMESPACE diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE new file mode 100644 index 00000000000..197576a5c63 --- /dev/null +++ b/R/rdeephaven/NAMESPACE @@ -0,0 +1,21 @@ +# Generated by roxygen2: do not edit by hand + +export(Client) +export(ClientOptions) +export(TableHandle) +export(agg.abs_sum) +export(agg.avg) +export(agg.count) +export(agg.first) +export(agg.last) +export(agg.max) +export(agg.median) +export(agg.min) +export(agg.percentile) +export(agg.std) +export(agg.sum) +export(agg.var) +export(agg.w_avg) +import(Rcpp) +importFrom(Rcpp,evalCpp) +useDynLib(rdeephaven, .registration = TRUE) \ No newline at end of file diff --git a/R/rdeephaven/R/aggregate_functions.R b/R/rdeephaven/R/aggregate_functions.R index eeda887c933..09b8e0a7560 100644 --- a/R/rdeephaven/R/aggregate_functions.R +++ b/R/rdeephaven/R/aggregate_functions.R @@ -1,64 +1,79 @@ #' @export agg.min = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_min(columns))) } #' @export agg.max = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_max(columns))) } #' @export agg.sum = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_sum(columns))) } #' @export agg.abs_sum = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_abs_sum(columns))) } #' @export agg.avg = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_avg(columns))) } #' @export agg.w_avg = function(weight_column, columns) { + verify_string(weight_column, "weight_column") + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) } #' @export agg.var = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_var(columns))) } #' @export agg.std = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_std(columns))) } #' @export agg.first = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_first(columns))) } #' @export agg.last = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_last(columns))) } #' @export agg.median = function(columns) { + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_median(columns))) } #' @export agg.percentile = function(percentile, columns) { + # TODO: type check percentile + verify_string_vector(columns, "columns") return(Aggregation$new(INTERNAL_percentile(percentile, columns))) } #' @export agg.count = function(count_column) { + verify_string(count_column, "count_column") return(Aggregation$new(INTERNAL_count(count_column))) } diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 408c8fa9a41..a8854b8c67f 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -3,20 +3,28 @@ first_class = function(arg) { } verify_string <- function(arg_name, string_candidate) { - if (class(string_candidate)[[1]] != "character") { - stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", class(string_candidate)[[1]], " instead.")) - } else if (length(string_candidate) != 1) { + if (first_class(string_candidate) != "character") { + stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", first_class(string_candidate), " instead.")) + } + else if (length(string_candidate) != 1) { stop(paste0("'", arg_name, "' must be passed as a single string. Got a character vector of length ", length(string_candidate), " instead.")) } } +verify_string_vector <- function(arg_name, string_vector_candidate) { + if (first_class(string_candidate) != "character") { + stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_candidate), " instead.")) +} + verify_int <- function(arg_name, int_candidate) { if (class(int_candidate)[[1]] != "numeric") { - stop(paste0("'", arg_name, "' must be an integer. Got an object of class ", class(int_candidate)[[1]], " instead.")) - } else if (all.equal(int_candidate, as.integer(int_candidate)) != TRUE) { + stop(paste0("'", arg_name, "' must be an integer. Got an object of class ", first_class(int_candidate), " instead.")) + } + else if (all.equal(int_candidate, as.integer(int_candidate)) != TRUE) { # must use != TRUE as the result of all.equal() is not strictly boolean stop(paste0("'", arg_name, "' must be an integer. Got a non-integer numeric type instead.")) - } else if (length(int_candidate) != 1) { + } + else if (length(int_candidate) != 1) { stop(paste0("'", arg_name, "' must be an integer. Got a numeric vector of length ", length(int_candidate), " instead.")) } } \ No newline at end of file diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index f0b14570dc3..13b1a0e6292 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -110,6 +110,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to select. #' @return A TableHandle referencing the new table. select = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$select(columns))) }, @@ -119,6 +120,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to view. #' @return A TableHandle referencing the new table. view = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$view(columns))) }, @@ -127,6 +129,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to exclude. #' @return A TableHandle referencing the new table. drop_columns = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$drop_columns(columns))) }, @@ -136,6 +139,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. #' @return A TableHandle referencing the new table. update = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$update(columns))) }, @@ -145,6 +149,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. #' @return A TableHandle referencing the new table. update_view = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$update_view(columns))) }, @@ -154,6 +159,7 @@ TableHandle <- R6Class("TableHandle", #' @param condition A Deephaven boolean expression such as "Price > 100" or "Col3 == Col1 * Col2". #' @return A TableHandle referencing the new table. where = function(condition) { + verify_string(condition, "condition") return(TableHandle$new(self$internal_table_handle$where(condition))) }, @@ -185,6 +191,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. min_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$min_by(columns))) }, @@ -194,6 +201,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. max_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$max_by(columns))) }, @@ -203,6 +211,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. sum_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$sum_by(columns))) }, @@ -212,6 +221,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. abs_sum_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$abs_sum_by(columns))) }, @@ -221,6 +231,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. avg_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$avg_by(columns))) }, @@ -231,6 +242,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. w_avg_by = function(weight_column, columns) { + verify_string(weight_column, "weight_column") + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$w_avg_by(weight_column, columns))) }, @@ -240,6 +253,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. var_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$var_by(columns))) }, @@ -249,6 +263,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. std_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$std_by(columns))) }, @@ -258,6 +273,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. first_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$first_by(columns))) }, @@ -267,6 +283,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. last_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$last_by(columns))) }, @@ -276,6 +293,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. median_by = function(columns) { + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$median_by(columns))) }, @@ -286,6 +304,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. percentile_by = function(percentile, columns) { + verify_string_vector(columns, "columns") + # TODO: type check percentile return(TableHandle$new(self$internal_table_handle$percentile_by(percentile, columns))) }, @@ -296,6 +316,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. count_by = function(count_by_column, columns) { + verify_string(count_by_column, "count_by_column") + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$count_by(count_by_column, columns))) }, @@ -306,6 +328,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. head_by = function(n, columns) { + verify_int(n, "n") + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$head_by(n, columns))) }, @@ -316,6 +340,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. tail_by = function(n, columns) { + verify_int(n, "n") + verify_string_vector(columns, "columns") return(TableHandle$new(self$internal_table_handle$tail_by(n, columns))) }, @@ -330,6 +356,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns_to_add The columns from the right side to add, and possibly rename. #' @return A TableHandle referencing the new table. cross_join = function(right_side, columns_to_match, columns_to_add) { + verify_string_vector(columns_to_match, "columns_to_match") + verify_string_vector(columns_to_add, "columns_to_add") return(TableHandle$new(self$internal_table_handle$cross_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, @@ -343,6 +371,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns_to_add The columns from the right side to add, and possibly rename. #' @return A TableHandle referencing the new table. natural_join = function(right_side, columns_to_match, columns_to_add) { + verify_string_vector(columns_to_match, "columns_to_match") + verify_string_vector(columns_to_add, "columns_to_add") return(TableHandle$new(self$internal_table_handle$natural_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, @@ -356,10 +386,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns_to_add The columns from the right side to add, and possibly rename. #' @return A TableHandle referencing the new table. exact_join = function(right_side, columns_to_match, columns_to_add) { - print(right_side) - print(columns_to_match) - print(columns_to_add) - print(right_side$internal_table_handle) + verify_string_vector(columns_to_match, "columns_to_match") + verify_string_vector(columns_to_add, "columns_to_add") return(TableHandle$new(self$internal_table_handle$exact_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, @@ -371,6 +399,7 @@ TableHandle <- R6Class("TableHandle", #' @param n Number of rows #' @return A TableHandle referencing the new table. head = function(n) { + verify_int(n, "n") return(TableHandle$new(self$internal_table_handle$head(n))) }, @@ -379,6 +408,7 @@ TableHandle <- R6Class("TableHandle", #' @param n Number of rows #' @return A TableHandle referencing the new table. tail = function(n) { + verify_int(n, "n") return(TableHandle$new(self$internal_table_handle$tail(n))) }, @@ -388,6 +418,7 @@ TableHandle <- R6Class("TableHandle", #' @param group_by_columns Columns to ungroup. #' @return A TableHandle referencing the new table. ungroup = function(null_fill, group_by_columns) { + verify_string_vector(group_by_columns, "group_by_columns") return(TableHandle$new(self$internal_table_handle$ungroup(null_fill, group_by_columns))) }, @@ -407,9 +438,10 @@ TableHandle <- R6Class("TableHandle", #TODO: Document keyColumn #' @param sources The tables to merge. #' @return A TableHandle referencing the new table. - #TODO: merge = function(key_column, sources) { - # return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) - #}, + merge = function(key_column, sources) { + verify_string(key_column, "key_column") + return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) + }, internal_table_handle = NULL ), diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 567c4f19262..d3f921135b6 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -11,13 +11,6 @@ #include #include -//#include -//class AggregateWrapper; -//namespace Rcpp { -// template <> SEXP wrap(const std::vector&); -// template <> std::vector as(SEXP); -//} - #include // forward declaration of classes @@ -26,6 +19,11 @@ class TableHandleWrapper; class ClientOptionsWrapper; class ClientWrapper; +// forward declaration of conversion functions +std::vector convertRcppListToVectorOfTypeAggregate(Rcpp::List rcpp_list); +std::vector convertRcppListToVectorOfTypeTableHandle(Rcpp::List rcpp_list); + + // ######################### DH WRAPPERS ######################### class AggregateWrapper { @@ -37,8 +35,23 @@ class AggregateWrapper { private: deephaven::client::Aggregate internal_aggregation; friend TableHandleWrapper; + friend std::vector convertRcppListToVectorOfTypeAggregate(Rcpp::List rcpp_list); }; +// ######################### conversion function for the above class +std::vector convertRcppListToVectorOfTypeAggregate(Rcpp::List rcpp_list) { + std::vector converted_list; + converted_list.reserve(rcpp_list.size()); + + for(int i = 0; i < rcpp_list.size(); i++) { + Rcpp::Environment rcpp_list_element = rcpp_list[i]; + Rcpp::XPtr xptr(rcpp_list_element.get(".pointer")); + deephaven::client::Aggregate internal_aggregation = xptr->internal_aggregation; + converted_list.push_back(internal_aggregation); + } + return converted_list; +} + AggregateWrapper* INTERNAL_min(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::min(columnSpecs)); } @@ -128,15 +141,7 @@ class TableHandleWrapper { // AGGREGATION OPERATIONS TableHandleWrapper* aggBy(Rcpp::List aggregations) { - std::vector converted_aggregations; - converted_aggregations.reserve(aggregations.size()); - - for(int i = 0; i < aggregations.size(); i++) { - Rcpp::Environment aggregation = aggregations[i]; - Rcpp::XPtr xptr(aggregation.get(".pointer")); - deephaven::client::Aggregate internal_aggregation = xptr->internal_aggregation; - converted_aggregations.push_back(internal_aggregation); - } + std::vector converted_aggregations = convertRcppListToVectorOfTypeAggregate(aggregations); return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations))); } @@ -232,14 +237,15 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.ungroup(nullFill, groupByColumns)); }; + TableHandleWrapper* merge(std::string keyColumn, Rcpp::List sources) { + std::vector converted_sources = convertRcppListToVectorOfTypeTableHandle(sources); + return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, converted_sources)); + }; + // TODO: TableHandleWrapper* sort(std::vector sortPairs) { // return new TableHandleWrapper(internal_tbl_hdl.sort(sortPairs)); // }; - // TODO: TableHandleWrapper* merge(std::string keyColumn, std::vector sources) { - // return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, convertTableHandleWrapperVector(sources))); - // }; - /** * Whether the table was static at the time internal_tbl_hdl was created. */ @@ -284,8 +290,23 @@ class TableHandleWrapper { private: deephaven::client::TableHandle internal_tbl_hdl; + friend std::vector convertRcppListToVectorOfTypeTableHandle(Rcpp::List rcpp_list); }; +// ######################### conversion function for the above class +std::vector convertRcppListToVectorOfTypeTableHandle(Rcpp::List rcpp_list) { + std::vector converted_list; + converted_list.reserve(rcpp_list.size()); + + for(int i = 0; i < rcpp_list.size(); i++) { + Rcpp::Environment rcpp_list_element = rcpp_list[i]; + Rcpp::XPtr xptr(rcpp_list_element.get(".pointer")); + deephaven::client::TableHandle internal_tbl_hdl = xptr->internal_tbl_hdl; + converted_list.push_back(internal_tbl_hdl); + } + return converted_list; +} + // TODO: Document this guy class ClientOptionsWrapper { @@ -481,8 +502,8 @@ RCPP_MODULE(DeephavenInternalModule) { .method("head", &TableHandleWrapper::head) .method("tail", &TableHandleWrapper::tail) .method("ungroup", &TableHandleWrapper::ungroup) + .method("merge", &TableHandleWrapper::merge) // TODO: .method("sort", &TableHandleWrapper::sort) - // TODO: .method("merge", &TableHandleWrapper::merge) .method("is_static", &TableHandleWrapper::isStatic) .method("num_rows", &TableHandleWrapper::numRows) From ec5339e7285b8f1a7d0e1ae5db7c768aef094576 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 19 Jul 2023 18:50:42 -0500 Subject: [PATCH 11/73] Fix helper functions, add Aggregation to NAMESPACE --- R/rdeephaven/NAMESPACE | 3 ++- R/rdeephaven/R/helper_functions.R | 1 + R/rdeephaven/man/TableHandle.Rd | 44 +++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 197576a5c63..a88ed0041f2 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +export(Aggregation) export(Client) export(ClientOptions) export(TableHandle) @@ -18,4 +19,4 @@ export(agg.var) export(agg.w_avg) import(Rcpp) importFrom(Rcpp,evalCpp) -useDynLib(rdeephaven, .registration = TRUE) \ No newline at end of file +useDynLib(rdeephaven, .registration = TRUE) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index a8854b8c67f..899984d15b1 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -14,6 +14,7 @@ verify_string <- function(arg_name, string_candidate) { verify_string_vector <- function(arg_name, string_vector_candidate) { if (first_class(string_candidate) != "character") { stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_candidate), " instead.")) + } } verify_int <- function(arg_name, int_candidate) { diff --git a/R/rdeephaven/man/TableHandle.Rd b/R/rdeephaven/man/TableHandle.Rd index 5e6bdaff918..37db00f86fb 100644 --- a/R/rdeephaven/man/TableHandle.Rd +++ b/R/rdeephaven/man/TableHandle.Rd @@ -45,7 +45,7 @@ new_table_handle2$bind_to_variable("new_table") \item \href{#method-TableHandle-update}{\code{TableHandle$update()}} \item \href{#method-TableHandle-update_view}{\code{TableHandle$update_view()}} \item \href{#method-TableHandle-where}{\code{TableHandle$where()}} -\item \href{#method-TableHandle-by}{\code{TableHandle$by()}} +\item \href{#method-TableHandle-agg_by}{\code{TableHandle$agg_by()}} \item \href{#method-TableHandle-min_by}{\code{TableHandle$min_by()}} \item \href{#method-TableHandle-max_by}{\code{TableHandle$max_by()}} \item \href{#method-TableHandle-sum_by}{\code{TableHandle$sum_by()}} @@ -67,6 +67,7 @@ new_table_handle2$bind_to_variable("new_table") \item \href{#method-TableHandle-head}{\code{TableHandle$head()}} \item \href{#method-TableHandle-tail}{\code{TableHandle$tail()}} \item \href{#method-TableHandle-ungroup}{\code{TableHandle$ungroup()}} +\item \href{#method-TableHandle-merge}{\code{TableHandle$merge()}} \item \href{#method-TableHandle-clone}{\code{TableHandle$clone()}} } } @@ -301,19 +302,18 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-by}{}}} -\subsection{Method \code{by()}}{ -Creates a new table from this table, grouped by columns with the column content grouped -into arrays. +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-agg_by}{}}} +\subsection{Method \code{agg_by()}}{ +Creates a new table from this table with one or more aggregations applied to the specified columns. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$by(columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$agg_by(aggregations)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{columns}}{Columns to group by.} +\item{\code{aggregations}}{Deephaven Aggregations to apply to this table.} } \if{html}{\out{
}} } @@ -786,6 +786,34 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-merge}{}}} +\subsection{Method \code{merge()}}{ +Creates a new table from this table, sorted by sortPairs. + + +Creates a new table by merging `sources` together. The tables are essentially stacked on top +of each other. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$merge(key_column, sources)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{sources}}{The tables to merge.} + +\item{\code{sort_pairs}}{A vector of SortPair objects describing the sort. Each SortPair refers to +a column, a sort direction, and whether the sort should consider to the value's regular or +absolute value when doing comparisons.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-TableHandle-clone}{}}} \subsection{Method \code{clone()}}{ From 3353842aad0cd7f6223225b8f027f7ffd800f57e Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 20 Jul 2023 10:58:40 -0500 Subject: [PATCH 12/73] Fix error handling, move unit tests to install automatically --- R/rdeephaven/R/aggregate_functions.R | 31 ++++---- R/rdeephaven/R/helper_functions.R | 13 +++- R/rdeephaven/R/table_handle_wrapper.R | 77 +++++++++---------- R/rdeephaven/{ => inst}/tests/testthat.R | 0 .../testthat/test_client_options_wrapper.R | 0 .../tests/testthat/test_client_wrapper.R | 0 .../testthat/test_table_handle_wrapper.R | 4 +- .../tests/testthat/test_table_operations.R | 0 8 files changed, 67 insertions(+), 58 deletions(-) rename R/rdeephaven/{ => inst}/tests/testthat.R (100%) rename R/rdeephaven/{ => inst}/tests/testthat/test_client_options_wrapper.R (100%) rename R/rdeephaven/{ => inst}/tests/testthat/test_client_wrapper.R (100%) rename R/rdeephaven/{ => inst}/tests/testthat/test_table_handle_wrapper.R (96%) rename R/rdeephaven/{ => inst}/tests/testthat/test_table_operations.R (100%) diff --git a/R/rdeephaven/R/aggregate_functions.R b/R/rdeephaven/R/aggregate_functions.R index 09b8e0a7560..0189b6cdac7 100644 --- a/R/rdeephaven/R/aggregate_functions.R +++ b/R/rdeephaven/R/aggregate_functions.R @@ -1,79 +1,80 @@ #' @export agg.min = function(columns) { - verify_string_vector(columns, "columns") + print("in function") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_min(columns))) } #' @export agg.max = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_max(columns))) } #' @export agg.sum = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_sum(columns))) } #' @export agg.abs_sum = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_abs_sum(columns))) } #' @export agg.avg = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_avg(columns))) } #' @export agg.w_avg = function(weight_column, columns) { - verify_string(weight_column, "weight_column") - verify_string_vector(columns, "columns") + verify_string("weight_column", weight_column) + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) } #' @export agg.var = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_var(columns))) } #' @export agg.std = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_std(columns))) } #' @export agg.first = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_first(columns))) } #' @export agg.last = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_last(columns))) } #' @export agg.median = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_median(columns))) } #' @export agg.percentile = function(percentile, columns) { - # TODO: type check percentile - verify_string_vector(columns, "columns") + verify_proportion("percentile", percentile) + verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_percentile(percentile, columns))) } #' @export agg.count = function(count_column) { - verify_string(count_column, "count_column") + verify_string("count_column", count_column) return(Aggregation$new(INTERNAL_count(count_column))) } diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 899984d15b1..0cd64c23c35 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -12,8 +12,8 @@ verify_string <- function(arg_name, string_candidate) { } verify_string_vector <- function(arg_name, string_vector_candidate) { - if (first_class(string_candidate) != "character") { - stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_candidate), " instead.")) + if (first_class(string_vector_candidate) != "character") { + stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_vector_candidate), " instead.")) } } @@ -28,4 +28,13 @@ verify_int <- function(arg_name, int_candidate) { else if (length(int_candidate) != 1) { stop(paste0("'", arg_name, "' must be an integer. Got a numeric vector of length ", length(int_candidate), " instead.")) } +} + +verify_proportion <- function(arg_name, prop_candidate) { + if (first_class(prop_candidate) != "numeric") { + stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got an object of class ", first_class(prop_candidate), " instead.")) + } + else if ((prop_candidate < 0.0) || (prop_candidate > 1.0)) { + stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a value outside of [0, 1] instead.")) + } } \ No newline at end of file diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 13b1a0e6292..b0b13b57ebf 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -32,8 +32,7 @@ TableHandle <- R6Class("TableHandle", initialize = function(table_handle) { if (first_class(table_handle) != "Rcpp_INTERNAL_TableHandle") { - stop("'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, - you are trying to call the constructor of TableHandle directly, which is not advised.") + stop("'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") } self$internal_table_handle <- table_handle private$is_static_field <- self$internal_table_handle$is_static() @@ -110,7 +109,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to select. #' @return A TableHandle referencing the new table. select = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$select(columns))) }, @@ -120,7 +119,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to view. #' @return A TableHandle referencing the new table. view = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$view(columns))) }, @@ -129,7 +128,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to exclude. #' @return A TableHandle referencing the new table. drop_columns = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$drop_columns(columns))) }, @@ -139,7 +138,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. #' @return A TableHandle referencing the new table. update = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$update(columns))) }, @@ -149,7 +148,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. #' @return A TableHandle referencing the new table. update_view = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$update_view(columns))) }, @@ -159,7 +158,7 @@ TableHandle <- R6Class("TableHandle", #' @param condition A Deephaven boolean expression such as "Price > 100" or "Col3 == Col1 * Col2". #' @return A TableHandle referencing the new table. where = function(condition) { - verify_string(condition, "condition") + verify_string("condition", condition) return(TableHandle$new(self$internal_table_handle$where(condition))) }, @@ -172,10 +171,10 @@ TableHandle <- R6Class("TableHandle", agg_by = function(aggregations) { if ((first_class(aggregations) == "list") && (any(lapply(aggregations, first_class) != "Aggregation"))) { - stop("dumb!!") + stop(paste0("'aggregations' must be a Deephaven Aggregation, or a vector of Aggregations. Got a vector with at least one element that is not a Deephaven Aggregation instead.")) } else if ((first_class(aggregations) != "list") && (first_class(aggregations) != "Aggregation")) { - stop("dumber!!") + stop(paste0("'aggregations' must be a Deephaven Aggregation, or a vector of Aggregations. Got an object of class ", first_class(aggregations), " instead.")) } else if ((first_class(aggregations) != "list") && (first_class(aggregations) == "Aggregation")) { aggregations = c(aggregations) @@ -191,7 +190,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. min_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$min_by(columns))) }, @@ -201,7 +200,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. max_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$max_by(columns))) }, @@ -211,7 +210,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. sum_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$sum_by(columns))) }, @@ -221,7 +220,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. abs_sum_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$abs_sum_by(columns))) }, @@ -231,7 +230,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. avg_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$avg_by(columns))) }, @@ -242,8 +241,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. w_avg_by = function(weight_column, columns) { - verify_string(weight_column, "weight_column") - verify_string_vector(columns, "columns") + verify_string("weight_column", weight_column) + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$w_avg_by(weight_column, columns))) }, @@ -253,7 +252,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. var_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$var_by(columns))) }, @@ -263,7 +262,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. std_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$std_by(columns))) }, @@ -273,7 +272,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. first_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$first_by(columns))) }, @@ -283,7 +282,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. last_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$last_by(columns))) }, @@ -293,7 +292,7 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. median_by = function(columns) { - verify_string_vector(columns, "columns") + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$median_by(columns))) }, @@ -304,8 +303,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. percentile_by = function(percentile, columns) { - verify_string_vector(columns, "columns") - # TODO: type check percentile + verify_proportion("percentile", percentile) + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$percentile_by(percentile, columns))) }, @@ -316,8 +315,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. count_by = function(count_by_column, columns) { - verify_string(count_by_column, "count_by_column") - verify_string_vector(columns, "columns") + verify_string("count_by_column", count_by_column) + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$count_by(count_by_column, columns))) }, @@ -328,8 +327,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. head_by = function(n, columns) { - verify_int(n, "n") - verify_string_vector(columns, "columns") + verify_int("n", n) + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$head_by(n, columns))) }, @@ -340,8 +339,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns Columns to group by. #' @return A TableHandle referencing the new table. tail_by = function(n, columns) { - verify_int(n, "n") - verify_string_vector(columns, "columns") + verify_int("n", n) + verify_string_vector("columns", columns) return(TableHandle$new(self$internal_table_handle$tail_by(n, columns))) }, @@ -356,8 +355,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns_to_add The columns from the right side to add, and possibly rename. #' @return A TableHandle referencing the new table. cross_join = function(right_side, columns_to_match, columns_to_add) { - verify_string_vector(columns_to_match, "columns_to_match") - verify_string_vector(columns_to_add, "columns_to_add") + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) return(TableHandle$new(self$internal_table_handle$cross_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, @@ -371,8 +370,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns_to_add The columns from the right side to add, and possibly rename. #' @return A TableHandle referencing the new table. natural_join = function(right_side, columns_to_match, columns_to_add) { - verify_string_vector(columns_to_match, "columns_to_match") - verify_string_vector(columns_to_add, "columns_to_add") + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) return(TableHandle$new(self$internal_table_handle$natural_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, @@ -386,8 +385,8 @@ TableHandle <- R6Class("TableHandle", #' @param columns_to_add The columns from the right side to add, and possibly rename. #' @return A TableHandle referencing the new table. exact_join = function(right_side, columns_to_match, columns_to_add) { - verify_string_vector(columns_to_match, "columns_to_match") - verify_string_vector(columns_to_add, "columns_to_add") + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) return(TableHandle$new(self$internal_table_handle$exact_join(right_side$internal_table_handle, columns_to_match, columns_to_add))) }, @@ -399,7 +398,7 @@ TableHandle <- R6Class("TableHandle", #' @param n Number of rows #' @return A TableHandle referencing the new table. head = function(n) { - verify_int(n, "n") + verify_int("n", n) return(TableHandle$new(self$internal_table_handle$head(n))) }, @@ -408,7 +407,7 @@ TableHandle <- R6Class("TableHandle", #' @param n Number of rows #' @return A TableHandle referencing the new table. tail = function(n) { - verify_int(n, "n") + verify_int("n", n) return(TableHandle$new(self$internal_table_handle$tail(n))) }, @@ -439,7 +438,7 @@ TableHandle <- R6Class("TableHandle", #' @param sources The tables to merge. #' @return A TableHandle referencing the new table. merge = function(key_column, sources) { - verify_string(key_column, "key_column") + verify_string("key_column", key_column) return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) }, diff --git a/R/rdeephaven/tests/testthat.R b/R/rdeephaven/inst/tests/testthat.R similarity index 100% rename from R/rdeephaven/tests/testthat.R rename to R/rdeephaven/inst/tests/testthat.R diff --git a/R/rdeephaven/tests/testthat/test_client_options_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R similarity index 100% rename from R/rdeephaven/tests/testthat/test_client_options_wrapper.R rename to R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R diff --git a/R/rdeephaven/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R similarity index 100% rename from R/rdeephaven/tests/testthat/test_client_wrapper.R rename to R/rdeephaven/inst/tests/testthat/test_client_wrapper.R diff --git a/R/rdeephaven/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R similarity index 96% rename from R/rdeephaven/tests/testthat/test_table_handle_wrapper.R rename to R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index bf9d8d61506..40e87caad95 100644 --- a/R/rdeephaven/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -152,8 +152,8 @@ test_that("to_data_frame returns a valid data frame", { test_that("trying to instantiate a TableHandle directly fails nicely", { - expect_error(TableHandle$new("hello!"), "'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, - you are trying to call the constructor of TableHandle directly, which is not advised.") + expect_error(TableHandle$new("hello!"), + "'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") }) test_that("bind_to_variable fails nicely on bad inputs", { diff --git a/R/rdeephaven/tests/testthat/test_table_operations.R b/R/rdeephaven/inst/tests/testthat/test_table_operations.R similarity index 100% rename from R/rdeephaven/tests/testthat/test_table_operations.R rename to R/rdeephaven/inst/tests/testthat/test_table_operations.R From 1da5870f1922beff2e47b3cc53dc1dc8f5d20298 Mon Sep 17 00:00:00 2001 From: Alex Peters <80283343+alexpeters1208@users.noreply.github.com> Date: Thu, 20 Jul 2023 11:02:00 -0500 Subject: [PATCH 13/73] Update README to simplify install command in light of automatic test installation --- R/rdeephaven/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/rdeephaven/README.md b/R/rdeephaven/README.md index 39a9c812f98..48136fdd1fb 100644 --- a/R/rdeephaven/README.md +++ b/R/rdeephaven/README.md @@ -82,7 +82,7 @@ Currently, the R client is only supported on Ubuntu 20.04 or 22.04 and must be b ``` then install the deephaven client itself: ```r - install.packages("/path/to/rdeephaven", INSTALL_opts="--install-tests", repos=NULL, type="source") + install.packages("/path/to/rdeephaven", repos=NULL, type="source") ``` This last command can also be executed from RStudio without the need for explicitly starting an R console. From 55bc0307d32093e32880b359ccf3b971af08e593 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 20 Jul 2023 17:26:31 -0500 Subject: [PATCH 14/73] Add Sorter class to make tableHandle.sort() work, change functions to not conflict with S3, more error handling, more unit tests --- R/rdeephaven/NAMESPACE | 29 +++-- R/rdeephaven/R/aggregate_functions.R | 80 ------------ R/rdeephaven/R/aggregate_wrapper.R | 88 ++++++++++++- R/rdeephaven/R/helper_functions.R | 41 ++++-- R/rdeephaven/R/sort_wrapper.R | 32 +++++ R/rdeephaven/R/table_handle_wrapper.R | 31 +++-- .../tests/testthat/test_aggregate_wrapper.R | 122 ++++++++++++++++++ .../inst/tests/testthat/test_sorter_wrapper.R | 45 +++++++ R/rdeephaven/man/TableHandle.Rd | 30 ++++- R/rdeephaven/src/client.cpp | 85 +++++++++--- 10 files changed, 436 insertions(+), 147 deletions(-) delete mode 100644 R/rdeephaven/R/aggregate_functions.R create mode 100644 R/rdeephaven/R/sort_wrapper.R create mode 100644 R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R create mode 100644 R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index a88ed0041f2..b7671490f03 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -3,20 +3,23 @@ export(Aggregation) export(Client) export(ClientOptions) +export(Sorter) export(TableHandle) -export(agg.abs_sum) -export(agg.avg) -export(agg.count) -export(agg.first) -export(agg.last) -export(agg.max) -export(agg.median) -export(agg.min) -export(agg.percentile) -export(agg.std) -export(agg.sum) -export(agg.var) -export(agg.w_avg) +export(agg_abs_sum) +export(agg_avg) +export(agg_count) +export(agg_first) +export(agg_last) +export(agg_max) +export(agg_median) +export(agg_min) +export(agg_percentile) +export(agg_std) +export(agg_sum) +export(agg_var) +export(agg_w_avg) +export(sort_asc) +export(sort_desc) import(Rcpp) importFrom(Rcpp,evalCpp) useDynLib(rdeephaven, .registration = TRUE) diff --git a/R/rdeephaven/R/aggregate_functions.R b/R/rdeephaven/R/aggregate_functions.R deleted file mode 100644 index 0189b6cdac7..00000000000 --- a/R/rdeephaven/R/aggregate_functions.R +++ /dev/null @@ -1,80 +0,0 @@ -#' @export -agg.min = function(columns) { - print("in function") - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_min(columns))) -} - -#' @export -agg.max = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_max(columns))) -} - -#' @export -agg.sum = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_sum(columns))) -} - -#' @export -agg.abs_sum = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_abs_sum(columns))) -} - -#' @export -agg.avg = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_avg(columns))) -} - -#' @export -agg.w_avg = function(weight_column, columns) { - verify_string("weight_column", weight_column) - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) -} - -#' @export -agg.var = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_var(columns))) -} - -#' @export -agg.std = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_std(columns))) -} - -#' @export -agg.first = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_first(columns))) -} - -#' @export -agg.last = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_last(columns))) -} - -#' @export -agg.median = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_median(columns))) -} - -#' @export -agg.percentile = function(percentile, columns) { - verify_proportion("percentile", percentile) - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_percentile(percentile, columns))) -} - -#' @export -agg.count = function(count_column) { - verify_string("count_column", count_column) - return(Aggregation$new(INTERNAL_count(count_column))) -} diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R index de92c33ae19..dc3be948cac 100644 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -6,13 +6,93 @@ Aggregation <- R6Class("Aggregation", #' Create an Aggregation instance. initialize = function(aggregation) { if (class(aggregation) != "Rcpp_INTERNAL_Aggregate") { - stop("'aggregation' should be an internal Deephaven Aggregation. If you're seeing this, - you are trying to call the constructor of an Aggregation directly, which is not advised. - Please use one of the provided aggregation functions instead.") + stop("'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead.") } self$internal_aggregation <- aggregation }, internal_aggregation = NULL ) -) \ No newline at end of file +) + +### All of the functions below return an instance of the above class + +#' @export +agg_min = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_min(columns))) +} + +#' @export +agg_max = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_max(columns))) +} + +#' @export +agg_sum = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_sum(columns))) +} + +#' @export +agg_abs_sum = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_abs_sum(columns))) +} + +#' @export +agg_avg = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_avg(columns))) +} + +#' @export +agg_w_avg = function(weight_column, columns) { + verify_string("weight_column", weight_column) + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) +} + +#' @export +agg_var = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_var(columns))) +} + +#' @export +agg_std = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_std(columns))) +} + +#' @export +agg_first = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_first(columns))) +} + +#' @export +agg_last = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_last(columns))) +} + +#' @export +agg_median = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_median(columns))) +} + +#' @export +agg_percentile = function(percentile, columns) { + verify_proportion("percentile", percentile) + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_percentile(percentile, columns))) +} + +#' @export +agg_count = function(count_column) { + verify_string("count_column", count_column) + return(Aggregation$new(INTERNAL_count(count_column))) +} \ No newline at end of file diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 0cd64c23c35..65e38583b5f 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -2,18 +2,21 @@ first_class = function(arg) { return(class(arg)[[1]]) } -verify_string <- function(arg_name, string_candidate) { - if (first_class(string_candidate) != "character") { - stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", first_class(string_candidate), " instead.")) +verify_internal_type <- function(desired_type, arg_name, candidate) { + if ((first_class(candidate) == "list") && (any(lapply(candidate, first_class) != desired_type))) { + stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got a vector with at least one element that is not a Deephaven ", desired_type, " instead.")) } - else if (length(string_candidate) != 1) { - stop(paste0("'", arg_name, "' must be passed as a single string. Got a character vector of length ", length(string_candidate), " instead.")) + else if ((first_class(candidate) != "list") && (first_class(candidate) != desired_type)) { + stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got an object of class ", first_class(candidate), " instead.")) } } -verify_string_vector <- function(arg_name, string_vector_candidate) { - if (first_class(string_vector_candidate) != "character") { - stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_vector_candidate), " instead.")) +verify_bool <- function(arg_name, bool_candidate) { + if (first_class(bool_candidate) != "logical") { + stop(paste0("'", arg_name, "' must be passed as a single boolean. Got an object of class ", first_class(bool_candidate), " instead.")) + } + else if (length(bool_candidate) != 1) { + stop(paste0("'", arg_name, "' must be passed as a single boolean. Got a boolean vector of length ", length(bool_candidate), " instead.")) } } @@ -34,7 +37,25 @@ verify_proportion <- function(arg_name, prop_candidate) { if (first_class(prop_candidate) != "numeric") { stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got an object of class ", first_class(prop_candidate), " instead.")) } + else if (length(prop_candidate) != 1) { + stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length ", length(prop_candidate), " instead.")) + } else if ((prop_candidate < 0.0) || (prop_candidate > 1.0)) { - stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a value outside of [0, 1] instead.")) + stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a value of ", prop_candidate, " instead.")) + } +} + +verify_string <- function(arg_name, string_candidate) { + if (first_class(string_candidate) != "character") { + stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", first_class(string_candidate), " instead.")) } -} \ No newline at end of file + else if (length(string_candidate) != 1) { + stop(paste0("'", arg_name, "' must be passed as a single string. Got a character vector of length ", length(string_candidate), " instead.")) + } +} + +verify_string_vector <- function(arg_name, string_vector_candidate) { + if (first_class(string_vector_candidate) != "character") { + stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_vector_candidate), " instead.")) + } +} diff --git a/R/rdeephaven/R/sort_wrapper.R b/R/rdeephaven/R/sort_wrapper.R new file mode 100644 index 00000000000..680ddc2e523 --- /dev/null +++ b/R/rdeephaven/R/sort_wrapper.R @@ -0,0 +1,32 @@ +#' @export +Sorter <- R6Class("Sorter", + public = list( + + #' @description + #' Create a Sorter instance. + initialize = function(sort_pair) { + if (class(sort_pair) != "Rcpp_INTERNAL_SortPair") { + stop("'sort_pair' should be an internal Deephaven SortPair. If you're seeing this,\n you are trying to call the constructor of a Sorter directly, which is not advised.\n Please use one of the provided sorting functions instead.") + } + self$internal_sorter <- sort_pair + }, + + internal_sorter = NULL + ) +) + +### All of the functions below return an instance of the above class + +#' @export +sort_asc <- function(column, abs=FALSE) { + verify_string("column", column) + verify_bool("abs", abs) + return(Sorter$new(INTERNAL_sort_asc(column, abs))) +} + +#' @export +sort_desc <- function(column, abs=FALSE) { + verify_string("column", column) + verify_bool("abs", abs) + return(Sorter$new(INTERNAL_sort_desc(column, abs))) +} \ No newline at end of file diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index b0b13b57ebf..4db102e5096 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -169,14 +169,8 @@ TableHandle <- R6Class("TableHandle", #' @param aggregations Deephaven Aggregations to apply to this table. #' @return A TableHandle referencing the new table. agg_by = function(aggregations) { - - if ((first_class(aggregations) == "list") && (any(lapply(aggregations, first_class) != "Aggregation"))) { - stop(paste0("'aggregations' must be a Deephaven Aggregation, or a vector of Aggregations. Got a vector with at least one element that is not a Deephaven Aggregation instead.")) - } - else if ((first_class(aggregations) != "list") && (first_class(aggregations) != "Aggregation")) { - stop(paste0("'aggregations' must be a Deephaven Aggregation, or a vector of Aggregations. Got an object of class ", first_class(aggregations), " instead.")) - } - else if ((first_class(aggregations) != "list") && (first_class(aggregations) == "Aggregation")) { + verify_internal_type("Aggregation", "aggregations", aggregations) + if ((first_class(aggregations) != "list") && (first_class(aggregations) == "Aggregation")) { aggregations = c(aggregations) } unwrapped_aggregations = lapply(aggregations, private$strip_r6_wrapping_from_aggregation) @@ -423,13 +417,18 @@ TableHandle <- R6Class("TableHandle", #' @description #' Creates a new table from this table, sorted by sortPairs. - #' @param sort_pairs A vector of SortPair objects describing the sort. Each SortPair refers to - #' a column, a sort direction, and whether the sort should consider to the value's regular or - #' absolute value when doing comparisons. + #' @param sorters A vector of Deephaven Sorter objects (either sort.asc or sort.desc) describing the sort. + #' Each Sorter accepts a column to sort, and whether the sort should consider to the value's regular or + #' absolute value when doing comparisons. #' @return A TableHandle referencing the new table. - # TODO: sort = function(sort_pairs) { - # return(TableHandle$new(self$internal_table_handle$sort(sort_pairs))) - #}, + sort = function(sorters) { + verify_internal_type("Sorter", "sorters", sorters) + if ((first_class(sorters) != "list") && (first_class(sorters) == "Sorter")) { + sorters = c(sorters) + } + unwrapped_sorters = lapply(sorters, private$strip_r6_wrapping_from_sorter) + return(TableHandle$new(self$internal_table_handle$sort(unwrapped_sorters))) + }, #' @description #' Creates a new table by merging `sources` together. The tables are essentially stacked on top @@ -450,6 +449,10 @@ TableHandle <- R6Class("TableHandle", return(r6_aggregation$internal_aggregation) }, + strip_r6_wrapping_from_sorter = function(r6_sorter) { + return(r6_sorter$internal_sorter) + }, + is_static_field = NULL ) ) diff --git a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R new file mode 100644 index 00000000000..24099c4f824 --- /dev/null +++ b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R @@ -0,0 +1,122 @@ +library(testthat) +library(rdeephaven) + +##### TESTING BAD INPUTS ##### + +test_that("trying to instantiate an Aggregation fails nicely", { + expect_error(Aggregation$new("hello"), + "'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead.") +}) + +test_that("agg_min fails nicely when 'columns' is a bad type", { + expect_error(agg_min(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_min(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_max fails nicely when 'columns' is a bad type", { + expect_error(agg_max(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_max(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_sum fails nicely when 'columns' is a bad type", { + expect_error(agg_sum(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_sum(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_abs_sum fails nicely when 'columns' is a bad type", { + expect_error(agg_abs_sum(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_abs_sum(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_avg fails nicely when 'columns' is a bad type", { + expect_error(agg_avg(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_avg(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_w_avg fails nicely when 'weight_column' is a bad type", { + expect_error(agg_w_avg(5, "string"), + "'weight_column' must be passed as a single string. Got an object of class numeric instead.") + expect_error(agg_w_avg(TRUE, "string"), + "'weight_column' must be passed as a single string. Got an object of class logical instead.") + expect_error(agg_w_avg(c("Multiple", "strings", "bad"), "string"), + "'weight_column' must be passed as a single string. Got a character vector of length 3 instead.") +}) + +test_that("agg_w_avg fails nicely when 'columns' is a bad type", { + expect_error(agg_w_avg("string", 5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_w_avg("string", TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_var fails nicely when 'columns' is a bad type", { + expect_error(agg_var(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_var(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_std fails nicely when 'columns' is a bad type", { + expect_error(agg_std(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_std(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_first fails nicely when 'columns' is a bad type", { + expect_error(agg_first(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_first(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_last fails nicely when 'columns' is a bad type", { + expect_error(agg_last(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_last(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_median fails nicely when 'columns' is a bad type", { + expect_error(agg_median(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_median(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_percentile fails nicely when 'percentile' is bad", { + expect_error(agg_percentile("string", "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class character instead.") + expect_error(agg_percentile(TRUE, "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class logical instead.") + expect_error(agg_percentile(5, "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got a value of 5 instead.") + expect_error(agg_percentile(c(5,6,7,8), "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length 4 instead.") +}) + +test_that("agg_percentile fails nicely when 'columns' is a bad type", { + expect_error(agg_percentile(0.5, 5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") + expect_error(agg_percentile(0.5, TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") +}) + +test_that("agg_count fails nicely when 'count_column' is a bad type", { + expect_error(agg_count(5), + "'count_column' must be passed as a single string. Got an object of class numeric instead.") + expect_error(agg_count(TRUE), + "'count_column' must be passed as a single string. Got an object of class logical instead.") + expect_error(agg_count(c("Many", "strings")), + "'count_column' must be passed as a single string. Got a character vector of length 2 instead.") +}) \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R new file mode 100644 index 00000000000..4280fa30b96 --- /dev/null +++ b/R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R @@ -0,0 +1,45 @@ +library(testthat) +library(rdeephaven) + +##### TESTING BAD INPUTS ##### + +test_that("trying to instantiate a Sorter fails nicely", { + expect_error(Sorter$new("hello"), + "'sort_pair' should be an internal Deephaven SortPair. If you're seeing this,\n you are trying to call the constructor of a Sorter directly, which is not advised.\n Please use one of the provided sorting functions instead.") +}) + +test_that("sort_asc fails when 'column' is a bad type", { + expect_error(sort_asc(5), + "'column' must be passed as a single string. Got an object of class numeric instead.") + expect_error(sort_asc(TRUE), + "'column' must be passed as a single string. Got an object of class logical instead.") + expect_error(sort_asc(c("a", "b", "c", "d")), + "'column' must be passed as a single string. Got a character vector of length 4 instead.") +}) + +test_that("sort_asc fails when 'abs' is a bad type", { + expect_error(sort_asc("string", abs=1), + "'abs' must be passed as a single boolean. Got an object of class numeric instead.") + expect_error(sort_asc("string", abs="hello!"), + "'abs' must be passed as a single boolean. Got an object of class character instead.") + expect_error(sort_asc("string", abs=c(TRUE, TRUE, FALSE)), + "'abs' must be passed as a single boolean. Got a boolean vector of length 3 instead.") +}) + +test_that("sort_desc fails when 'column' is a bad type", { + expect_error(sort_desc(5), + "'column' must be passed as a single string. Got an object of class numeric instead.") + expect_error(sort_desc(TRUE), + "'column' must be passed as a single string. Got an object of class logical instead.") + expect_error(sort_desc(c("a", "b", "c", "d")), + "'column' must be passed as a single string. Got a character vector of length 4 instead.") +}) + +test_that("sort_desc fails when 'abs' is a bad type", { + expect_error(sort_desc("string", abs=1), + "'abs' must be passed as a single boolean. Got an object of class numeric instead.") + expect_error(sort_desc("string", abs="hello!"), + "'abs' must be passed as a single boolean. Got an object of class character instead.") + expect_error(sort_desc("string", abs=c(TRUE, TRUE, FALSE)), + "'abs' must be passed as a single boolean. Got a boolean vector of length 3 instead.") +}) \ No newline at end of file diff --git a/R/rdeephaven/man/TableHandle.Rd b/R/rdeephaven/man/TableHandle.Rd index 37db00f86fb..437af1e75ce 100644 --- a/R/rdeephaven/man/TableHandle.Rd +++ b/R/rdeephaven/man/TableHandle.Rd @@ -67,6 +67,7 @@ new_table_handle2$bind_to_variable("new_table") \item \href{#method-TableHandle-head}{\code{TableHandle$head()}} \item \href{#method-TableHandle-tail}{\code{TableHandle$tail()}} \item \href{#method-TableHandle-ungroup}{\code{TableHandle$ungroup()}} +\item \href{#method-TableHandle-sort}{\code{TableHandle$sort()}} \item \href{#method-TableHandle-merge}{\code{TableHandle$merge()}} \item \href{#method-TableHandle-clone}{\code{TableHandle$clone()}} } @@ -786,12 +787,31 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-sort}{}}} +\subsection{Method \code{sort()}}{ +Creates a new table from this table, sorted by sortPairs. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TableHandle$sort(sorters)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{sorters}}{A vector of Deephaven Sorter objects (either sort.asc or sort.desc) describing the sort. +Each Sorter accepts a column to sort, and whether the sort should consider to the value's regular or +absolute value when doing comparisons.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +A TableHandle referencing the new table. +} +} +\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-TableHandle-merge}{}}} \subsection{Method \code{merge()}}{ -Creates a new table from this table, sorted by sortPairs. - - Creates a new table by merging `sources` together. The tables are essentially stacked on top of each other. \subsection{Usage}{ @@ -802,10 +822,6 @@ of each other. \if{html}{\out{
}} \describe{ \item{\code{sources}}{The tables to merge.} - -\item{\code{sort_pairs}}{A vector of SortPair objects describing the sort. Each SortPair refers to -a column, a sort direction, and whether the sort should consider to the value's regular or -absolute value when doing comparisons.} } \if{html}{\out{
}} } diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index d3f921135b6..a73a0751ea8 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -5,6 +5,7 @@ #include #include "deephaven/client/client.h" +#include "deephaven/client/columns.h" #include "deephaven/client/flight.h" #include "deephaven/client/utility/arrow_util.h" @@ -18,10 +19,12 @@ class AggregateWrapper; class TableHandleWrapper; class ClientOptionsWrapper; class ClientWrapper; +class SortPairWrapper; // forward declaration of conversion functions std::vector convertRcppListToVectorOfTypeAggregate(Rcpp::List rcpp_list); std::vector convertRcppListToVectorOfTypeTableHandle(Rcpp::List rcpp_list); +std::vector convertRcppListToVectorOfTypeSortPair(Rcpp::List rcpp_list); // ######################### DH WRAPPERS ######################### @@ -30,8 +33,7 @@ class AggregateWrapper { public: AggregateWrapper(); AggregateWrapper(deephaven::client::Aggregate aggregate) : - internal_aggregation(std::move(aggregate)) { - } + internal_aggregation(std::move(aggregate)) {} private: deephaven::client::Aggregate internal_aggregation; friend TableHandleWrapper; @@ -105,6 +107,40 @@ AggregateWrapper* INTERNAL_count(std::string columnSpec) { } +class SortPairWrapper { +public: + SortPairWrapper(); + SortPairWrapper(deephaven::client::SortPair sort_pair) : + internal_sorter(std::move(sort_pair)) {} +private: + deephaven::client::SortPair internal_sorter; + friend TableHandleWrapper; + friend std::vector convertRcppListToVectorOfTypeSortPair(Rcpp::List rcpp_list); +}; + +// ######################### conversion function for the above class +std::vector convertRcppListToVectorOfTypeSortPair(Rcpp::List rcpp_list) { + std::vector converted_list; + converted_list.reserve(rcpp_list.size()); + + for(int i = 0; i < rcpp_list.size(); i++) { + Rcpp::Environment rcpp_list_element = rcpp_list[i]; + Rcpp::XPtr xptr(rcpp_list_element.get(".pointer")); + deephaven::client::SortPair internal_sorter = xptr->internal_sorter; + converted_list.push_back(internal_sorter); + } + return converted_list; +} + +SortPairWrapper* INTERNAL_sortAsc(std::string column, bool abs) { + return new SortPairWrapper(deephaven::client::SortPair::ascending(column, abs)); +} + +SortPairWrapper* INTERNAL_sortDesc(std::string column, bool abs) { + return new SortPairWrapper(deephaven::client::SortPair::descending(column, abs)); +} + + class TableHandleWrapper { public: TableHandleWrapper(deephaven::client::TableHandle ref_table) : @@ -242,9 +278,10 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, converted_sources)); }; - // TODO: TableHandleWrapper* sort(std::vector sortPairs) { - // return new TableHandleWrapper(internal_tbl_hdl.sort(sortPairs)); - // }; + TableHandleWrapper* sort(Rcpp::List sortPairs) { + std::vector converted_sort_pairs = convertRcppListToVectorOfTypeSortPair(sortPairs); + return new TableHandleWrapper(internal_tbl_hdl.sort(converted_sort_pairs)); + }; /** * Whether the table was static at the time internal_tbl_hdl was created. @@ -463,12 +500,33 @@ using namespace Rcpp; RCPP_EXPOSED_CLASS(ClientOptionsWrapper) RCPP_EXPOSED_CLASS(TableHandleWrapper) RCPP_EXPOSED_CLASS(AggregateWrapper) +RCPP_EXPOSED_CLASS(SortPairWrapper) RCPP_EXPOSED_CLASS(ArrowArrayStream) RCPP_MODULE(DeephavenInternalModule) { class_("INTERNAL_Aggregate") ; + function("INTERNAL_min", &INTERNAL_min); + function("INTERNAL_max", &INTERNAL_max); + function("INTERNAL_sum", &INTERNAL_sum); + function("INTERNAL_abs_sum", &INTERNAL_absSum); + function("INTERNAL_avg", &INTERNAL_avg); + function("INTERNAL_w_avg", &INTERNAL_wAvg); + function("INTERNAL_var", &INTERNAL_var); + function("INTERNAL_std", &INTERNAL_std); + function("INTERNAL_first", &INTERNAL_first); + function("INTERNAL_last", &INTERNAL_last); + function("INTERNAL_median", &INTERNAL_median); + function("INTERNAL_percentile", &INTERNAL_percentile); + function("INTERNAL_count", &INTERNAL_count); + + + class_("INTERNAL_SortPair") + ; + function("INTERNAL_sort_asc", &INTERNAL_sortAsc); + function("INTERNAL_sort_desc", &INTERNAL_sortDesc); + class_("INTERNAL_TableHandle") .method("select", &TableHandleWrapper::select) @@ -503,7 +561,7 @@ RCPP_MODULE(DeephavenInternalModule) { .method("tail", &TableHandleWrapper::tail) .method("ungroup", &TableHandleWrapper::ungroup) .method("merge", &TableHandleWrapper::merge) - // TODO: .method("sort", &TableHandleWrapper::sort) + .method("sort", &TableHandleWrapper::sort) .method("is_static", &TableHandleWrapper::isStatic) .method("num_rows", &TableHandleWrapper::numRows) @@ -511,6 +569,7 @@ RCPP_MODULE(DeephavenInternalModule) { .method("get_arrow_array_stream_ptr", &TableHandleWrapper::getArrowArrayStreamPtr) ; + class_("INTERNAL_ClientOptions") .constructor() .method("set_default_authentication", &ClientOptionsWrapper::setDefaultAuthentication) @@ -524,6 +583,7 @@ RCPP_MODULE(DeephavenInternalModule) { .method("add_extra_header", &ClientOptionsWrapper::addExtraHeader) ; + class_("INTERNAL_Client") .constructor() .method("open_table", &ClientWrapper::openTable) @@ -535,17 +595,4 @@ RCPP_MODULE(DeephavenInternalModule) { .method("new_table_from_arrow_array_stream_ptr", &ClientWrapper::newTableFromArrowArrayStreamPtr) ; - function("INTERNAL_min", &INTERNAL_min); - function("INTERNAL_max", &INTERNAL_max); - function("INTERNAL_sum", &INTERNAL_sum); - function("INTERNAL_abs_sum", &INTERNAL_absSum); - function("INTERNAL_avg", &INTERNAL_avg); - function("INTERNAL_w_avg", &INTERNAL_wAvg); - function("INTERNAL_var", &INTERNAL_var); - function("INTERNAL_std", &INTERNAL_std); - function("INTERNAL_first", &INTERNAL_first); - function("INTERNAL_last", &INTERNAL_last); - function("INTERNAL_median", &INTERNAL_median); - function("INTERNAL_percentile", &INTERNAL_percentile); - function("INTERNAL_count", &INTERNAL_count); } From 57ed26ca4d068d5e67357a16f04bc66f8b20958a Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 21 Jul 2023 17:22:43 -0500 Subject: [PATCH 15/73] More unit tests --- R/rdeephaven/R/table_handle_wrapper.R | 18 +- .../tests/testthat/test_table_operations.R | 185 +++++++++++++++++- R/rdeephaven/src/client.cpp | 10 +- 3 files changed, 190 insertions(+), 23 deletions(-) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 4db102e5096..aa987318348 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -123,15 +123,6 @@ TableHandle <- R6Class("TableHandle", return(TableHandle$new(self$internal_table_handle$view(columns))) }, - #' @description - #' Creates a new table from this table where the specified columns have been excluded. - #' @param columns The columns to exclude. - #' @return A TableHandle referencing the new table. - drop_columns = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$drop_columns(columns))) - }, - #' @description #' Creates a new table from this table, but including the additional specified columns. #' See the Deephaven documentation for the difference between update() and updateView(). @@ -152,6 +143,15 @@ TableHandle <- R6Class("TableHandle", return(TableHandle$new(self$internal_table_handle$update_view(columns))) }, + #' @description + #' Creates a new table from this table where the specified columns have been excluded. + #' @param columns The columns to exclude. + #' @return A TableHandle referencing the new table. + drop_columns = function(columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(self$internal_table_handle$drop_columns(columns))) + }, + #' @description #' Creates a new table from this table, filtered by condition. Consult the Deephaven #' documentation for more information about valid conditions. diff --git a/R/rdeephaven/inst/tests/testthat/test_table_operations.R b/R/rdeephaven/inst/tests/testthat/test_table_operations.R index 7fa68d00da9..d8aebb4757c 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_operations.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_operations.R @@ -16,6 +16,11 @@ setup <- function() { df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[250000], bool_col = sample(c(TRUE, FALSE), 250000, TRUE), int_col = sample(0:10000, 250000, TRUE)) + + df5 <- data.frame(X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), + Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), + Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214)) # in order to test TableHandle, we need to have tables on the server that we know everything about. # thus, we have to push these created tables to the server and get TableHandles to each of them. @@ -30,56 +35,218 @@ setup <- function() { th2 <- client$import_table(df2) th3 <- client$import_table(df3) th4 <- client$import_table(df4) + th5 <- client$import_table(df5) return(list("client" = client, - "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4)) + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5)) } ##### TESTING GOOD INPUTS ##### test_that("select behaves as expected", { data <- setup() + + expect_equal(data$th1$select("string_col")$to_data_frame(), data$df1["string_col"]) + + expect_equal(data$th2$select(c("col2", "col3"))$to_data_frame(), data$df2[c("col2", "col3")]) + + renamed_col_df3 <- data$df3[c("X1", "X2")] + colnames(renamed_col_df3)[1] = "first_col" + expect_equal(data$th3$select(c("first_col = X1", "X2"))$to_data_frame(), renamed_col_df3) + + new_col_df4 <- data$df4["int_col"] + 1 + colnames(new_col_df4) = "new_col" + expect_equal(data$th4$select("new_col = int_col + 1")$to_data_frame(), new_col_df4) + }) test_that("view behaves as expected", { data <- setup() -}) - -test_that("drop_columns behaves as expected", { - data <- setup() + + expect_equal(data$th1$view("string_col")$to_data_frame(), data$df1["string_col"]) + + expect_equal(data$th2$view(c("col2", "col3"))$to_data_frame(), data$df2[c("col2", "col3")]) + + renamed_col_df3 <- data$df3[c("X1", "X2")] + colnames(renamed_col_df3)[1] = "first_col" + expect_equal(data$th3$view(c("first_col = X1", "X2"))$to_data_frame(), renamed_col_df3) + + new_col_df4 <- data$df4["int_col"] + 1 + colnames(new_col_df4) = "new_col" + expect_equal(data$th4$view("new_col = int_col + 1")$to_data_frame(), new_col_df4) }) test_that("update behaves as expected", { data <- setup() + + new_df1 <- data$df1 + new_df1["dbl_col_again"] = new_df1["dbl_col"] + expect_equal(data$th1$update("dbl_col_again = dbl_col")$to_data_frame(), new_df1) + + new_df2 <- data$df2 + new_df2["col4"] = new_df2["col3"] * 2 + expect_equal(data$th2$update("col4 = col3 * 2")$to_data_frame(), new_df2) + + new_df3 <- data$df3 + new_df3["X1001"] = new_df3["X1000"] + new_df3["X1002"] = new_df3["X1001"] + expect_equal(data$th3$update(c("X1001 = X1000", "X1002 = X1001"))$to_data_frame(), new_df3) + + new_df4 <- data$df4 + new_df4["new_col"] = sqrt(3 * new_df4["int_col"]) + expect_equal(data$th4$update("new_col = sqrt(3 * int_col)")$to_data_frame(), new_df4) }) test_that("update_view behaves as expected", { data <- setup() + + new_df1 <- data$df1 + new_df1["dbl_col_again"] = new_df1["dbl_col"] + expect_equal(data$th1$update_view("dbl_col_again = dbl_col")$to_data_frame(), new_df1) + + new_df2 <- data$df2 + new_df2["col4"] = new_df2["col3"] * 2 + expect_equal(data$th2$update_view("col4 = col3 * 2")$to_data_frame(), new_df2) + + new_df3 <- data$df3 + new_df3["X1001"] = new_df3["X1000"] + new_df3["X1002"] = new_df3["X1001"] + expect_equal(data$th3$update_view(c("X1001 = X1000", "X1002 = X1001"))$to_data_frame(), new_df3) + + new_df4 <- data$df4 + new_df4["new_col"] = sqrt(3 * new_df4["int_col"]) + expect_equal(data$th4$update_view("new_col = sqrt(3 * int_col)")$to_data_frame(), new_df4) }) -test_that("where behaves as expected", { - data <- setup() +test_that("drop_columns behaves as expected", { + data <- setup() + + expect_equal(data$th1$drop_columns("string_col")$to_data_frame(), data$df1[c("int_col", "dbl_col")]) + + expect_equal(data$th2$drop_columns(c("col1", "col2"))$to_data_frame(), data$df2["col3"]) + + expect_equal(data$th3$drop_columns(paste0("X", seq(2, 1000)))$to_data_frame(), data$df3["X1"]) }) -test_that("by behaves as expected", { +test_that("where behaves as expected", { data <- setup() + + expect_equal(data$th1$where("int_col < 3")$to_data_frame(), data$df1[-c(4,5),]) + + expect_equal(data$th2$where("col2 == `hello!`")$to_data_frame(), data$df2) + + new_df3 <- data$df3[data$df3["X1"] - data$df3["X4"] + data$df3["X8"] + data$df3["X32"] - 2*data$df3["X5"] >= 0,] + rownames(new_df3) <- NULL + expect_equal(data$th3$where("X1 - X4 + X8 + X32 - 2*X5 >= 0")$to_data_frame(), new_df3) }) test_that("min_by behaves as expected", { data <- setup() + + expect_equal(data$th1$min_by("int_col")$to_data_frame(), data$df1[c("int_col", "string_col", "dbl_col")]) + + new_df2 <- data$df2 %>% + group_by(col2) %>% + summarise(across(everything(), min)) + expect_equal(data$th2$min_by("col2")$to_data_frame(), as.data.frame(new_df2)) + + new_df3 <- data$df3 %>% + mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% + group_by(bool_col1, bool_col2) %>% + summarise(across(everything(), min)) %>% + arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same + new_th3 <- data$th3$ + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0"))$ + min_by(c("bool_col1", "bool_col2"))$ + sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same + expect_equal(new_th3$to_data_frame(), as.data.frame(new_df3)) + + new_df4 <- data$df4 %>% + group_by(bool_col) %>% + summarise(across(everything(), min)) %>% + arrange(bool_col) + new_th4 <- data$th4$ + min_by("bool_col")$ + sort(sort_asc("bool_col")) + expect_equal(new_th4$to_data_frame(), as.data.frame(new_df4)) }) test_that("max_by behaves as expected", { data <- setup() + + expect_equal(data$th1$max_by("int_col")$to_data_frame(), data$df1[c("int_col", "string_col", "dbl_col")]) + + new_df2 <- data$df2 %>% + group_by(col2) %>% + summarise(across(everything(), max)) + expect_equal(data$th2$max_by("col2")$to_data_frame(), as.data.frame(new_df2)) + + new_df3 <- data$df3 %>% + mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% + group_by(bool_col1, bool_col2) %>% + summarise(across(everything(), max)) %>% + arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same + new_th3 <- data$th3$ + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0"))$ + max_by(c("bool_col1", "bool_col2"))$ + sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same + expect_equal(new_th3$to_data_frame(), as.data.frame(new_df3)) + + new_df4 <- data$df4 %>% + group_by(bool_col) %>% + summarise(across(everything(), max)) %>% + arrange(bool_col) + new_th4 <- data$th4$ + max_by("bool_col")$ + sort(sort_asc("bool_col")) + expect_equal(new_th4$to_data_frame(), as.data.frame(new_df4)) }) test_that("sum_by behaves as expected", { data <- setup() + + new_df5_1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), sum)) + new_th5_1 <- data$th5$ + drop_columns("Y")$ + sum_by("X") + expect_equal(new_th5_1$to_data_frame(), as.data.frame(new_df5_1)) + + new_df5_2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), sum)) %>% + arrange(X, Y) + new_th5_2 <- data$th5$ + sum_by(c("X", "Y"))$ + sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(new_th5_2$to_data_frame(), as.data.frame(new_df5_2)) }) test_that("abs_sum_by behaves as expected", { data <- setup() + + new_df5_1 <- data$df5 %>% + mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), sum)) + new_th5_1 <- data$th5$ + drop_columns("Y")$ + abs_sum_by("X") + expect_equal(new_th5_1$to_data_frame(), as.data.frame(new_df5_1)) + + new_df5_2 <- data$df5 %>% + mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% + group_by(X, Y) %>% + summarise(across(everything(), sum)) %>% + arrange(X, Y) + new_th5_2 <- data$th5$ + abs_sum_by(c("X", "Y"))$ + sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(new_th5_2$to_data_frame(), as.data.frame(new_df5_2)) }) test_that("var_by behaves as expected", { diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index a73a0751ea8..c46fb3f97e4 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -158,10 +158,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.view(columnSpecs)); }; - TableHandleWrapper* dropColumns(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.dropColumns(columnSpecs)); - }; - TableHandleWrapper* update(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.update(columnSpecs)); }; @@ -170,6 +166,10 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.updateView(columnSpecs)); }; + TableHandleWrapper* dropColumns(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.dropColumns(columnSpecs)); + }; + TableHandleWrapper* where(std::string condition) { return new TableHandleWrapper(internal_tbl_hdl.where(condition)); }; @@ -531,9 +531,9 @@ RCPP_MODULE(DeephavenInternalModule) { class_("INTERNAL_TableHandle") .method("select", &TableHandleWrapper::select) .method("view", &TableHandleWrapper::view) - .method("drop_columns", &TableHandleWrapper::dropColumns) .method("update", &TableHandleWrapper::update) .method("update_view", &TableHandleWrapper::updateView) + .method("drop_columns", &TableHandleWrapper::dropColumns) .method("where", &TableHandleWrapper::where) .method("agg_by", &TableHandleWrapper::aggBy) From bb997a60e7b18437fbfc7caceb1ec1ad8512edd4 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 24 Jul 2023 17:27:13 -0500 Subject: [PATCH 16/73] Overhaul table ops API for Dplyr feel --- R/rdeephaven/NAMESPACE | 5 + R/rdeephaven/R/aggregate_wrapper.R | 2 +- R/rdeephaven/R/client_options_wrapper.R | 2 +- R/rdeephaven/R/client_wrapper.R | 2 +- R/rdeephaven/R/helper_functions.R | 8 + R/rdeephaven/R/sort_wrapper.R | 2 +- R/rdeephaven/R/table_handle_wrapper.R | 371 +-------------- R/rdeephaven/R/table_ops.R | 271 +++++++++++ .../tests/testthat/test_table_operations.R | 437 +++++++++++++----- R/rdeephaven/man/TableHandle.Rd | 38 +- R/rdeephaven/src/client.cpp | 8 +- 11 files changed, 649 insertions(+), 497 deletions(-) create mode 100644 R/rdeephaven/R/table_ops.R diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index b7671490f03..78a3fb7e37d 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -1,5 +1,10 @@ # Generated by roxygen2: do not edit by hand +S3method(as.data.frame,TableHandle) +S3method(nrow,TableHandle) +S3method(select,TableHandle) +S3method(view,TableHandle) + export(Aggregation) export(Client) export(ClientOptions) diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R index dc3be948cac..b7377c30ff2 100644 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -1,5 +1,5 @@ #' @export -Aggregation <- R6Class("Aggregation", +Aggregation <- R6Class("Aggregation", cloneable = FALSE, public = list( #' @description diff --git a/R/rdeephaven/R/client_options_wrapper.R b/R/rdeephaven/R/client_options_wrapper.R index a4577fcc735..80c6ab93818 100644 --- a/R/rdeephaven/R/client_options_wrapper.R +++ b/R/rdeephaven/R/client_options_wrapper.R @@ -33,7 +33,7 @@ #' client <- Client$new(target="url/to/secure/server", client_options=client_options) #' @export -ClientOptions <- R6Class("ClientOptions", +ClientOptions <- R6Class("ClientOptions", cloneable = FALSE, public = list( #' @description diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index b2b16bb279f..3586aea994d 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -23,7 +23,7 @@ #' client$run_script("print([i for i in range(10)])") #' @export -Client <- R6Class("Client", +Client <- R6Class("Client", cloneable = FALSE, public = list( #' @description diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 65e38583b5f..988800afdfb 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -59,3 +59,11 @@ verify_string_vector <- function(arg_name, string_vector_candidate) { stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_vector_candidate), " instead.")) } } + +strip_r6_wrapping_from_aggregation = function(r6_aggregation) { + return(r6_aggregation$internal_aggregation) +} + +strip_r6_wrapping_from_sorter = function(r6_sorter) { + return(r6_sorter$internal_sorter) +} \ No newline at end of file diff --git a/R/rdeephaven/R/sort_wrapper.R b/R/rdeephaven/R/sort_wrapper.R index 680ddc2e523..7ae10f40e03 100644 --- a/R/rdeephaven/R/sort_wrapper.R +++ b/R/rdeephaven/R/sort_wrapper.R @@ -1,5 +1,5 @@ #' @export -Sorter <- R6Class("Sorter", +Sorter <- R6Class("Sorter", cloneable = FALSE, public = list( #' @description diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index aa987318348..a0aed706bf5 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -1,33 +1,33 @@ #' @title Deephaven TableHandles #' @description Deephaven TableHandles are references to tables living on a Deephaven server. They provide an #' interface for interacting with tables on the server. -#' +#' #' @usage NULL #' @format NULL #' @docType class #' #' @examples -#' +#' #' # connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication #' client_options <- ClientOptions$new() #' client <- Client$new(target="localhost:10000", client_options=client_options) -#' +#' #' # open a table that already exists on the server #' new_table_handle1 <- client$open_table("table_on_the_server") -#' +#' #' # convert the Deephaven table to an R data frame #' new_data_frame <- new_table_handle1$to_data_frame() -#' +#' #' # modify new data frame in R #' new_data_frame$New_Int_Col <- c(1, 2, 3, 4, 5) #' new_data_frame$New_String_Col <- c("I", "am", "a", "string", "column") -#' +#' #' # push new data frame to the server and name it "new_table" #' new_table_handle2 <- client$import_table(new_data_frame) #' new_table_handle2$bind_to_variable("new_table") #' @export -TableHandle <- R6Class("TableHandle", +TableHandle <- R6Class("TableHandle", cloneable = FALSE, public = list( initialize = function(table_handle) { @@ -98,361 +98,18 @@ TableHandle <- R6Class("TableHandle", arrow_tbl = self$to_arrow_table() return(as.data.frame(as.data.frame(arrow_tbl))) # TODO: for some reason as.data.frame on arrow table returns a tibble, not a data frame }, - - ###################### TABLE OPERATIONS ####################### - - # FILTERING OPERATIONS - - #' @description - #' Select columns from a table. The columns can be column names or formulas like - #' "NewCol = A + 12". See the Deephaven documentation for the difference between "select" and "view". - #' @param columns The columns to select. - #' @return A TableHandle referencing the new table. - select = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$select(columns))) - }, - - #' @description - #' View columns from a table. The columns can be column names or formulas like - #' "NewCol = A + 12". See the Deephaven documentation for the difference between select() and view(). - #' @param columns The columns to view. - #' @return A TableHandle referencing the new table. - view = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$view(columns))) - }, - - #' @description - #' Creates a new table from this table, but including the additional specified columns. - #' See the Deephaven documentation for the difference between update() and updateView(). - #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. - #' @return A TableHandle referencing the new table. - update = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$update(columns))) - }, - - #' @description - #' Creates a new view from this table, but including the additional specified columns. - #' See the Deephaven documentation for the difference between update() and updateView(). - #' @param columns The columns to add. For example, {"X = A + 5", "Y = X * 2"}. - #' @return A TableHandle referencing the new table. - update_view = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$update_view(columns))) - }, - - #' @description - #' Creates a new table from this table where the specified columns have been excluded. - #' @param columns The columns to exclude. - #' @return A TableHandle referencing the new table. - drop_columns = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$drop_columns(columns))) - }, - - #' @description - #' Creates a new table from this table, filtered by condition. Consult the Deephaven - #' documentation for more information about valid conditions. - #' @param condition A Deephaven boolean expression such as "Price > 100" or "Col3 == Col1 * Col2". - #' @return A TableHandle referencing the new table. - where = function(condition) { - verify_string("condition", condition) - return(TableHandle$new(self$internal_table_handle$where(condition))) - }, - - # AGGREGATION OPERATIONS - - #' @description - #' Creates a new table from this table with one or more aggregations applied to the specified columns. - #' @param aggregations Deephaven Aggregations to apply to this table. - #' @return A TableHandle referencing the new table. - agg_by = function(aggregations) { - verify_internal_type("Aggregation", "aggregations", aggregations) - if ((first_class(aggregations) != "list") && (first_class(aggregations) == "Aggregation")) { - aggregations = c(aggregations) - } - unwrapped_aggregations = lapply(aggregations, private$strip_r6_wrapping_from_aggregation) - - return(TableHandle$new(self$internal_table_handle$agg_by(unwrapped_aggregations))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "min" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - min_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$min_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "max" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - max_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$max_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "sum" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - sum_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$sum_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "absSum" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - abs_sum_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$abs_sum_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "avg" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - avg_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$avg_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, having a new column named by - #' `weightColumn` containing the weighted average of each group. - #' @param weight_column Name of the output column. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - w_avg_by = function(weight_column, columns) { - verify_string("weight_column", weight_column) - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$w_avg_by(weight_column, columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "var" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - var_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$var_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "std" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - std_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$std_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "first" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - first_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$first_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "last" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - last_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$last_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "median" aggregate operation - #' applied to the remaining columns. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - median_by = function(columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$median_by(columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, with the "percentile" aggregate operation - #' applied to the remaining columns. - #' @param percentile The designated percentile - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - percentile_by = function(percentile, columns) { - verify_proportion("percentile", percentile) - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$percentile_by(percentile, columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, having a new column named by - #' `countByColumn` containing the size of each group. - #' @param count_by_column Name of the output column. - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - count_by = function(count_by_column, columns) { - verify_string("count_by_column", count_by_column) - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$count_by(count_by_column, columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, containing the first `n` rows of - #' each group. - #' @param n Number of rows - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - head_by = function(n, columns) { - verify_int("n", n) - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$head_by(n, columns))) - }, - - #' @description - #' Creates a new table from this table, grouped by columns, containing the last `n` rows of - #' each group. - #' @param n Number of rows - #' @param columns Columns to group by. - #' @return A TableHandle referencing the new table. - tail_by = function(n, columns) { - verify_int("n", n) - verify_string_vector("columns", columns) - return(TableHandle$new(self$internal_table_handle$tail_by(n, columns))) - }, - - # JOIN OPERATIONS - - #' @description - #' Creates a new table by cross joining this table with `rightSide`. The tables are joined by - #' the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally - #' renamed by `columnsToAdd`. Example: - #' @param right_side The table to join with this table - #' @param columns_to_match The columns to join on - #' @param columns_to_add The columns from the right side to add, and possibly rename. - #' @return A TableHandle referencing the new table. - cross_join = function(right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) - return(TableHandle$new(self$internal_table_handle$cross_join(right_side$internal_table_handle, - columns_to_match, columns_to_add))) - }, - - #' @description - #' Creates a new table by natural joining this table with `rightSide`. The tables are joined by - #' the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally - #' renamed by `columnsToAdd`. Example: - #' @param right_side The table to join with this table - #' @param columns_to_match The columns to join on - #' @param columns_to_add The columns from the right side to add, and possibly rename. - #' @return A TableHandle referencing the new table. - natural_join = function(right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) - return(TableHandle$new(self$internal_table_handle$natural_join(right_side$internal_table_handle, - columns_to_match, columns_to_add))) - }, - - #' @description - #' Creates a new table by exact joining this table with `rightSide`. The tables are joined by - #' the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally - #' renamed by `columnsToAdd`. Example: - #' @param right_side The table to join with this table - #' @param columns_to_match The columns to join on - #' @param columns_to_add The columns from the right side to add, and possibly rename. - #' @return A TableHandle referencing the new table. - exact_join = function(right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) - return(TableHandle$new(self$internal_table_handle$exact_join(right_side$internal_table_handle, - columns_to_match, columns_to_add))) - }, - - # MISC OPERATIONS - - #' @description - #' Creates a new table from this table containing the first `n` rows of this table. - #' @param n Number of rows - #' @return A TableHandle referencing the new table. - head = function(n) { - verify_int("n", n) - return(TableHandle$new(self$internal_table_handle$head(n))) - }, - - #' @description - #' Creates a new table from this table containing the last `n` rows of this table. - #' @param n Number of rows - #' @return A TableHandle referencing the new table. - tail = function(n) { - verify_int("n", n) - return(TableHandle$new(self$internal_table_handle$tail(n))) - }, - - #' @description - #' Creates a new table from this table with the column array data ungrouped. This is the inverse - #' of the by() const operation. - #' @param group_by_columns Columns to ungroup. - #' @return A TableHandle referencing the new table. - ungroup = function(null_fill, group_by_columns) { - verify_string_vector(group_by_columns, "group_by_columns") - return(TableHandle$new(self$internal_table_handle$ungroup(null_fill, group_by_columns))) - }, - - #' @description - #' Creates a new table from this table, sorted by sortPairs. - #' @param sorters A vector of Deephaven Sorter objects (either sort.asc or sort.desc) describing the sort. - #' Each Sorter accepts a column to sort, and whether the sort should consider to the value's regular or - #' absolute value when doing comparisons. - #' @return A TableHandle referencing the new table. - sort = function(sorters) { - verify_internal_type("Sorter", "sorters", sorters) - if ((first_class(sorters) != "list") && (first_class(sorters) == "Sorter")) { - sorters = c(sorters) - } - unwrapped_sorters = lapply(sorters, private$strip_r6_wrapping_from_sorter) - return(TableHandle$new(self$internal_table_handle$sort(unwrapped_sorters))) - }, - - #' @description - #' Creates a new table by merging `sources` together. The tables are essentially stacked on top - #' of each other. - #TODO: Document keyColumn - #' @param sources The tables to merge. - #' @return A TableHandle referencing the new table. - merge = function(key_column, sources) { - verify_string("key_column", key_column) - return(TableHandle$new(self$internal_table_handle$merge(key_column, sources))) - }, internal_table_handle = NULL ), private = list( - strip_r6_wrapping_from_aggregation = function(r6_aggregation) { - return(r6_aggregation$internal_aggregation) - }, - - strip_r6_wrapping_from_sorter = function(r6_sorter) { - return(r6_sorter$internal_sorter) - }, - is_static_field = NULL ) ) + +### S3 METHODS + +#' @export +as.data.frame.TableHandle <- function(x, ...) { + x$to_data_frame() +} diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R new file mode 100644 index 00000000000..6522e4c8a3d --- /dev/null +++ b/R/rdeephaven/R/table_ops.R @@ -0,0 +1,271 @@ +### S3 GENERICS +# The following generics do not already exist in the dplyr suite, so we must define them in order to implement the +# corresponding methods for TableHandles, so that the Deephaven query language feels identical to the dplyr experience. + +#' @export +view <- function(x, ...) {UseMethod("view", x)} +#' @export +update_view <- function(x, ...) {UseMethod("update_view", x)} +#' @export +drop_columns <- function(x, ...) {UseMethod("drop_columns", x)} +#' @export +where <- function(x, ...) {UseMethod("where", x)} + +#' @export +abs_sum_by <- function(x, ...) {UseMethod("abs_sum_by", x)} +#' @export +agg_by <- function(x, ...) {UseMethod("agg_by", x)} +#' @export +avg_by <- function(x, ...) {UseMethod("avg_by", x)} +#' @export +count_by <- function(x, ...) {UseMethod("count_by", x)} +#' @export +first_by <- function(x, ...) {UseMethod("first_by", x)} +#' @export +head_by <- function(x, ...) {UseMethod("head_by", x)} +#' @export +last_by <- function(x, ...) {UseMethod("last_by", x)} +#' @export +max_by <- function(x, ...) {UseMethod("max_by", x)} +#' @export +median_by <- function(x, ...) {UseMethod("median_by", x)} +#' @export +min_by <- function(x, ...) {UseMethod("min_by", x)} +#' @export +percentile_by <- function(x, ...) {UseMethod("percentile_by", x)} +#' @export +std_by <- function(x, ...) {UseMethod("std_by", x)} +#' @export +sum_by <- function(x, ...) {UseMethod("sum_by", x)} +#' @export +tail_by <- function(x, ...) {UseMethod("tail_by", x)} +#' @export +var_by <- function(x, ...) {UseMethod("var_by", x)} +#' @export +w_avg_by <- function(x, ...) {UseMethod("w_avg_by", x)} + +#' @export +cross_join <- function(x, ...) {UseMethod("cross_join", x)} +#' @export +natural_join <- function(x, ...) {UseMethod("natural_join", x)} +#' @export +exact_join <- function(x, ...) {UseMethod("exact_join", x)} + +# TODO: figure this shit out +#' @export +dh_ungroup <- function(x, ...) {UseMethod("dh_ungroup", x)} +#' @export +dh_sort <- function(x, ...) {UseMethod("dh_sort", x)} +#' @export +dh_merge <- function(x, ...) {UseMethod("dh_merge", x)} +#' @export +dh_cross_join <- function(x, ...) {UseMethod("dh_cross_join", x)} + + +### S3 METHODS (implemented generics) + +#' @export +select.TableHandle <- function(th, columns) { + verify_string_vector("columns", columns) + TableHandle$new(th$internal_table_handle$select(columns)) +} + +#' @export +view.TableHandle <- function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$view(columns))) +} + +#' @export +update.TableHandle <- function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$update(columns))) +} + +#' @export +update_view.TableHandle <- function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$update_view(columns))) +} + +#' @export +drop_columns.TableHandle <- function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$drop_columns(columns))) +} + +#' @export +where.TableHandle = function(th, condition) { + verify_string("condition", condition) + return(TableHandle$new(th$internal_table_handle$where(condition))) +} + +# AGGREGATION OPERATIONS + +#' @export +agg_by.TableHandle = function(th, aggregations) { + verify_internal_type("Aggregation", "aggregations", aggregations) + if ((first_class(aggregations) != "list") && (first_class(aggregations) == "Aggregation")) { + aggregations = c(aggregations) + } + unwrapped_aggregations = lapply(aggregations, strip_r6_wrapping_from_aggregation) + + return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations))) +} + +#' @export +min_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$min_by(columns))) +} + +#' @export +max_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$max_by(columns))) +} + +#' @export +sum_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$sum_by(columns))) +} + +#' @export +abs_sum_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) +} + +#' @export +avg_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$avg_by(columns))) +} + +#' @export +w_avg_by.TableHandle = function(th, weight_column, columns) { + verify_string("weight_column", weight_column) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) +} + +#' @export +var_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$var_by(columns))) +} + +#' @export +std_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$std_by(columns))) +} + +#' @export +first_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$first_by(columns))) +} + +#' @export +last_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$last_by(columns))) +} + +#' @export +median_by.TableHandle = function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$median_by(columns))) +} + +#' @export +percentile_by.TableHandle = function(th, columns, percentile) { + verify_string_vector("columns", columns) + verify_proportion("percentile", percentile) + return(TableHandle$new(th$internal_table_handle$percentile_by(columns, percentile))) +} + +#' @export +count_by.TableHandle = function(th, columns, count_by_column) { + verify_string("count_by_column", count_by_column) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) +} + +#' @export +head_by.TableHandle = function(th, columns, n) { + verify_int("n", n) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) +} + +#' @export +tail_by.TableHandle = function(th, columns, n) { + verify_int("n", n) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) +} + +# JOIN OPERATIONS + +#' @export +dh_cross_join.TableHandle = function(th, right_side, columns_to_match, columns_to_add) { + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) + return(TableHandle$new(th$internal_table_handle$cross_join(right_side$internal_table_handle, + columns_to_match, columns_to_add))) +} + +#' @export +natural_join.TableHandle = function(th, right_side, columns_to_match, columns_to_add) { + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) + return(TableHandle$new(th$internal_table_handle$natural_join(right_side$internal_table_handle, + columns_to_match, columns_to_add))) +} + +#' @export +exact_join.TableHandle = function(th, right_side, columns_to_match, columns_to_add) { + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) + return(TableHandle$new(th$internal_table_handle$exact_join(right_side$internal_table_handle, + columns_to_match, columns_to_add))) +} + +# MISC OPERATIONS + +#' @export +head.TableHandle = function(th, n) { + verify_int("n", n) + return(TableHandle$new(th$internal_table_handle$head(n))) +} + +#' @export +tail.TableHandle = function(th, n) { + verify_int("n", n) + return(TableHandle$new(th$internal_table_handle$tail(n))) +} + +#' @export +dh_ungroup.TableHandle = function(th, null_fill, group_by_columns) { + verify_string_vector(group_by_columns, "group_by_columns") + return(TableHandle$new(th$internal_table_handle$ungroup(null_fill, group_by_columns))) +} + +#' @export +dh_sort.TableHandle = function(th, sorters) { + verify_internal_type("Sorter", "sorters", sorters) + if ((first_class(sorters) != "list") && (first_class(sorters) == "Sorter")) { + sorters = c(sorters) + } + unwrapped_sorters = lapply(sorters, strip_r6_wrapping_from_sorter) + return(TableHandle$new(th$internal_table_handle$sort(unwrapped_sorters))) +} + +#' @export +dh_merge.TableHandle = function(th, key_column, sources) { + verify_string("key_column", key_column) + return(TableHandle$new(th$internal_table_handle$merge(key_column, sources))) +} \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_table_operations.R b/R/rdeephaven/inst/tests/testthat/test_table_operations.R index d8aebb4757c..545da904dda 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_operations.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_operations.R @@ -47,230 +47,441 @@ setup <- function() { test_that("select behaves as expected", { data <- setup() - expect_equal(data$th1$select("string_col")$to_data_frame(), data$df1["string_col"]) - - expect_equal(data$th2$select(c("col2", "col3"))$to_data_frame(), data$df2[c("col2", "col3")]) - - renamed_col_df3 <- data$df3[c("X1", "X2")] - colnames(renamed_col_df3)[1] = "first_col" - expect_equal(data$th3$select(c("first_col = X1", "X2"))$to_data_frame(), renamed_col_df3) - - new_col_df4 <- data$df4["int_col"] + 1 - colnames(new_col_df4) = "new_col" - expect_equal(data$th4$select("new_col = int_col + 1")$to_data_frame(), new_col_df4) - + new_tb1 <- data$df1 %>% + select("string_col") + new_th1 <- data$th1 %>% + select("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + select(c("col2", "col3")) + new_th2 <- data$th2 %>% + select(c("col2", "col3")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + select(c("X1", "X2")) %>% + rename(first_col = X1) + new_th3 <- data$th3 %>% + select(c("first_col = X1", "X2")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + select("int_col") %>% + mutate(new_col = int_col + 1, .keep = "none") + new_th4 <- data$th4 %>% + select("new_col = int_col + 1") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 * Number2) %>% + select(c("X", "Number3")) + new_th5 <- data$th5 %>% + select(c("X", "Number3 = Number1 * Number2")) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) }) test_that("view behaves as expected", { data <- setup() - expect_equal(data$th1$view("string_col")$to_data_frame(), data$df1["string_col"]) - - expect_equal(data$th2$view(c("col2", "col3"))$to_data_frame(), data$df2[c("col2", "col3")]) - - renamed_col_df3 <- data$df3[c("X1", "X2")] - colnames(renamed_col_df3)[1] = "first_col" - expect_equal(data$th3$view(c("first_col = X1", "X2"))$to_data_frame(), renamed_col_df3) - - new_col_df4 <- data$df4["int_col"] + 1 - colnames(new_col_df4) = "new_col" - expect_equal(data$th4$view("new_col = int_col + 1")$to_data_frame(), new_col_df4) + new_tb1 <- data$df1 %>% + select("string_col") + new_th1 <- data$th1 %>% + view("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + select(c("col2", "col3")) + new_th2 <- data$th2 %>% + view(c("col2", "col3")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + select(c("X1", "X2")) %>% + rename(first_col = X1) + new_th3 <- data$th3 %>% + view(c("first_col = X1", "X2")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + select("int_col") %>% + mutate(new_col = int_col + 1, .keep = "none") + new_th4 <- data$th4 %>% + view("new_col = int_col + 1") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 * Number2) %>% + select(c("X", "Number3")) + new_th5 <- data$th5 %>% + view(c("X", "Number3 = Number1 * Number2")) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) }) test_that("update behaves as expected", { data <- setup() - new_df1 <- data$df1 - new_df1["dbl_col_again"] = new_df1["dbl_col"] - expect_equal(data$th1$update("dbl_col_again = dbl_col")$to_data_frame(), new_df1) - - new_df2 <- data$df2 - new_df2["col4"] = new_df2["col3"] * 2 - expect_equal(data$th2$update("col4 = col3 * 2")$to_data_frame(), new_df2) - - new_df3 <- data$df3 - new_df3["X1001"] = new_df3["X1000"] - new_df3["X1002"] = new_df3["X1001"] - expect_equal(data$th3$update(c("X1001 = X1000", "X1002 = X1001"))$to_data_frame(), new_df3) - - new_df4 <- data$df4 - new_df4["new_col"] = sqrt(3 * new_df4["int_col"]) - expect_equal(data$th4$update("new_col = sqrt(3 * int_col)")$to_data_frame(), new_df4) + new_tb1 <- data$df1 %>% + mutate(dbl_col_again = dbl_col) + new_th1 <- data$th1 %>% + update("dbl_col_again = dbl_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + mutate(col4 = col3 * 2) + new_th2 <- data$th2 %>% + update("col4 = col3 * 2") + expect_equal(as.data.frame(new_tb2), as.data.frame(new_th2)) + + new_tb3 <- data$df3 %>% + mutate(X1001 = X1000, X1002 = X1001) + new_th3 <- data$th3 %>% + update(c("X1001 = X1000", "X1002 = X1001")) + expect_equal(as.data.frame(new_tb3), as.data.frame(new_th3)) + + new_tb4 <- data$df4 %>% + mutate(new_col = sqrt(3 * int_col)) + new_th4 <- data$th4 %>% + update("new_col = sqrt(3 * int_col)") + expect_equal(as.data.frame(new_tb4), as.data.frame(new_th4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 + Number2) + new_th5 <- data$th5 %>% + update("Number3 = Number1 + Number2") + expect_equal(as.data.frame(new_tb5), as.data.frame(new_th5)) }) test_that("update_view behaves as expected", { data <- setup() - new_df1 <- data$df1 - new_df1["dbl_col_again"] = new_df1["dbl_col"] - expect_equal(data$th1$update_view("dbl_col_again = dbl_col")$to_data_frame(), new_df1) - - new_df2 <- data$df2 - new_df2["col4"] = new_df2["col3"] * 2 - expect_equal(data$th2$update_view("col4 = col3 * 2")$to_data_frame(), new_df2) - - new_df3 <- data$df3 - new_df3["X1001"] = new_df3["X1000"] - new_df3["X1002"] = new_df3["X1001"] - expect_equal(data$th3$update_view(c("X1001 = X1000", "X1002 = X1001"))$to_data_frame(), new_df3) - - new_df4 <- data$df4 - new_df4["new_col"] = sqrt(3 * new_df4["int_col"]) - expect_equal(data$th4$update_view("new_col = sqrt(3 * int_col)")$to_data_frame(), new_df4) + new_tb1 <- data$df1 %>% + mutate(dbl_col_again = dbl_col) + new_th1 <- data$th1 %>% + update_view("dbl_col_again = dbl_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + mutate(col4 = col3 * 2) + new_th2 <- data$th2 %>% + update_view("col4 = col3 * 2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + mutate(X1001 = X1000, X1002 = X1001) + new_th3 <- data$th3 %>% + update_view(c("X1001 = X1000", "X1002 = X1001")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + mutate(new_col = sqrt(3 * int_col)) + new_th4 <- data$th4 %>% + update_view("new_col = sqrt(3 * int_col)") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 + Number2) + new_th5 <- data$th5 %>% + update_view("Number3 = Number1 + Number2") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) }) test_that("drop_columns behaves as expected", { data <- setup() - expect_equal(data$th1$drop_columns("string_col")$to_data_frame(), data$df1[c("int_col", "dbl_col")]) + new_tb1 <- data$df1 %>% + select(-"string_col") + new_th1 <- data$th1 %>% + drop_columns("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - expect_equal(data$th2$drop_columns(c("col1", "col2"))$to_data_frame(), data$df2["col3"]) + new_tb2 <- data$df2 %>% + select(-c("col1", "col2")) + new_th2 <- data$th2 %>% + drop_columns(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - expect_equal(data$th3$drop_columns(paste0("X", seq(2, 1000)))$to_data_frame(), data$df3["X1"]) + new_tb3 <- data$df3 %>% + select(-paste0("X", seq(2, 1000))) + new_th3 <- data$th3 %>% + drop_columns(paste0("X", seq(2, 1000))) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) }) test_that("where behaves as expected", { data <- setup() - - expect_equal(data$th1$where("int_col < 3")$to_data_frame(), data$df1[-c(4,5),]) - - expect_equal(data$th2$where("col2 == `hello!`")$to_data_frame(), data$df2) - new_df3 <- data$df3[data$df3["X1"] - data$df3["X4"] + data$df3["X8"] + data$df3["X32"] - 2*data$df3["X5"] >= 0,] - rownames(new_df3) <- NULL - expect_equal(data$th3$where("X1 - X4 + X8 + X32 - 2*X5 >= 0")$to_data_frame(), new_df3) + new_tb1 <- data$df1 %>% + filter(int_col < 3) + new_th1 <- data$th1 %>% + where("int_col < 3") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + filter(col2 == "hello!") + new_th2 <- data$th2 %>% + where("col2 == `hello!`") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + filter(X1 - X4 + X8 + X32 - 2*X5 >= 0) + new_th3 <- data$th3 %>% + where("X1 - X4 + X8 + X32 - 2*X5 >= 0") + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) }) test_that("min_by behaves as expected", { data <- setup() - expect_equal(data$th1$min_by("int_col")$to_data_frame(), data$df1[c("int_col", "string_col", "dbl_col")]) + new_tb1 <- data$df1 %>% + group_by(int_col) %>% + summarise(across(everything(), min)) + new_th1 <- data$th1 %>% + min_by("int_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - new_df2 <- data$df2 %>% + new_tb2 <- data$df2 %>% group_by(col2) %>% summarise(across(everything(), min)) - expect_equal(data$th2$min_by("col2")$to_data_frame(), as.data.frame(new_df2)) + new_th2 <- data$th2 %>% + min_by("col2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - new_df3 <- data$df3 %>% + new_tb3 <- data$df3 %>% mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% group_by(bool_col1, bool_col2) %>% summarise(across(everything(), min)) %>% arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same - new_th3 <- data$th3$ - update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0"))$ - min_by(c("bool_col1", "bool_col2"))$ - sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same - expect_equal(new_th3$to_data_frame(), as.data.frame(new_df3)) - - new_df4 <- data$df4 %>% + new_th3 <- data$th3 %>% + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% + min_by(c("bool_col1", "bool_col2")) %>% + dh_sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% group_by(bool_col) %>% summarise(across(everything(), min)) %>% arrange(bool_col) - new_th4 <- data$th4$ - min_by("bool_col")$ - sort(sort_asc("bool_col")) - expect_equal(new_th4$to_data_frame(), as.data.frame(new_df4)) + new_th4 <- data$th4 %>% + min_by("bool_col") %>% + dh_sort(sort_asc("bool_col")) + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) }) test_that("max_by behaves as expected", { data <- setup() - expect_equal(data$th1$max_by("int_col")$to_data_frame(), data$df1[c("int_col", "string_col", "dbl_col")]) + new_tb1 <- data$df1 %>% + group_by(int_col) %>% + summarise(across(everything(), max)) + new_th1 <- data$th1 %>% + max_by("int_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - new_df2 <- data$df2 %>% + new_tb2 <- data$df2 %>% group_by(col2) %>% summarise(across(everything(), max)) - expect_equal(data$th2$max_by("col2")$to_data_frame(), as.data.frame(new_df2)) + new_th2 <- data$th2 %>% + max_by("col2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - new_df3 <- data$df3 %>% + new_tb3 <- data$df3 %>% mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% group_by(bool_col1, bool_col2) %>% summarise(across(everything(), max)) %>% arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same - new_th3 <- data$th3$ - update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0"))$ - max_by(c("bool_col1", "bool_col2"))$ - sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same - expect_equal(new_th3$to_data_frame(), as.data.frame(new_df3)) + new_th3 <- data$th3 %>% + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% + max_by(c("bool_col1", "bool_col2")) %>% + dh_sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - new_df4 <- data$df4 %>% + new_tb4 <- data$df4 %>% group_by(bool_col) %>% summarise(across(everything(), max)) %>% arrange(bool_col) - new_th4 <- data$th4$ - max_by("bool_col")$ - sort(sort_asc("bool_col")) - expect_equal(new_th4$to_data_frame(), as.data.frame(new_df4)) + new_th4 <- data$th4 %>% + max_by("bool_col") %>% + dh_sort(sort_asc("bool_col")) + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) }) test_that("sum_by behaves as expected", { data <- setup() - new_df5_1 <- data$df5 %>% + new_tb1 <- data$df5 %>% select(-Y) %>% group_by(X) %>% summarise(across(everything(), sum)) - new_th5_1 <- data$th5$ - drop_columns("Y")$ + new_th1 <- data$th5 %>% + drop_columns("Y") %>% sum_by("X") - expect_equal(new_th5_1$to_data_frame(), as.data.frame(new_df5_1)) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - new_df5_2 <- data$df5 %>% + new_tb2 <- data$df5 %>% group_by(X, Y) %>% summarise(across(everything(), sum)) %>% arrange(X, Y) - new_th5_2 <- data$th5$ - sum_by(c("X", "Y"))$ - sort(c(sort_asc("X"), sort_asc("Y"))) - expect_equal(new_th5_2$to_data_frame(), as.data.frame(new_df5_2)) + new_th2 <- data$th5 %>% + sum_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("abs_sum_by behaves as expected", { data <- setup() - new_df5_1 <- data$df5 %>% - mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% + new_tb1 <- data$df5 %>% select(-Y) %>% + mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% group_by(X) %>% summarise(across(everything(), sum)) - new_th5_1 <- data$th5$ - drop_columns("Y")$ + new_th1 <- data$th5 %>% + drop_columns("Y") %>% abs_sum_by("X") - expect_equal(new_th5_1$to_data_frame(), as.data.frame(new_df5_1)) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - new_df5_2 <- data$df5 %>% + new_tb2 <- data$df5 %>% mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% group_by(X, Y) %>% summarise(across(everything(), sum)) %>% arrange(X, Y) - new_th5_2 <- data$th5$ - abs_sum_by(c("X", "Y"))$ - sort(c(sort_asc("X"), sort_asc("Y"))) - expect_equal(new_th5_2$to_data_frame(), as.data.frame(new_df5_2)) + new_th2 <- data$th5 %>% + abs_sum_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("var_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), var)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + var_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), var)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + var_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("std_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), sd)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + std_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), sd)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + std_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("avg_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), mean)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + avg_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), mean)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + avg_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("first_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), first)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + first_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), first)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + first_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("last_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), last)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + last_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), last)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + last_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("median_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), median)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + median_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), median)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + median_by(c("X", "Y")) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("percentile_by behaves as expected", { diff --git a/R/rdeephaven/man/TableHandle.Rd b/R/rdeephaven/man/TableHandle.Rd index 437af1e75ce..c353673a401 100644 --- a/R/rdeephaven/man/TableHandle.Rd +++ b/R/rdeephaven/man/TableHandle.Rd @@ -41,9 +41,9 @@ new_table_handle2$bind_to_variable("new_table") \item \href{#method-TableHandle-to_data_frame}{\code{TableHandle$to_data_frame()}} \item \href{#method-TableHandle-select}{\code{TableHandle$select()}} \item \href{#method-TableHandle-view}{\code{TableHandle$view()}} -\item \href{#method-TableHandle-drop_columns}{\code{TableHandle$drop_columns()}} \item \href{#method-TableHandle-update}{\code{TableHandle$update()}} \item \href{#method-TableHandle-update_view}{\code{TableHandle$update_view()}} +\item \href{#method-TableHandle-drop_columns}{\code{TableHandle$drop_columns()}} \item \href{#method-TableHandle-where}{\code{TableHandle$where()}} \item \href{#method-TableHandle-agg_by}{\code{TableHandle$agg_by()}} \item \href{#method-TableHandle-min_by}{\code{TableHandle$min_by()}} @@ -220,18 +220,19 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-drop_columns}{}}} -\subsection{Method \code{drop_columns()}}{ -Creates a new table from this table where the specified columns have been excluded. +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-update}{}}} +\subsection{Method \code{update()}}{ +Creates a new table from this table, but including the additional specified columns. +See the Deephaven documentation for the difference between update() and updateView(). \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$drop_columns(columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$update(columns)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{columns}}{The columns to exclude.} +\item{\code{columns}}{The columns to add. For example, {"X = A + 5", "Y = X * 2"}.} } \if{html}{\out{
}} } @@ -240,13 +241,13 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-update}{}}} -\subsection{Method \code{update()}}{ -Creates a new table from this table, but including the additional specified columns. +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-update_view}{}}} +\subsection{Method \code{update_view()}}{ +Creates a new view from this table, but including the additional specified columns. See the Deephaven documentation for the difference between update() and updateView(). \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$update(columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$update_view(columns)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -261,19 +262,18 @@ A TableHandle referencing the new table. } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-update_view}{}}} -\subsection{Method \code{update_view()}}{ -Creates a new view from this table, but including the additional specified columns. -See the Deephaven documentation for the difference between update() and updateView(). +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TableHandle-drop_columns}{}}} +\subsection{Method \code{drop_columns()}}{ +Creates a new table from this table where the specified columns have been excluded. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$update_view(columns)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{TableHandle$drop_columns(columns)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{columns}}{The columns to add. For example, {"X = A + 5", "Y = X * 2"}.} +\item{\code{columns}}{The columns to exclude.} } \if{html}{\out{
}} } diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index c46fb3f97e4..54533ce8c79 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -229,19 +229,19 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.medianBy(columnSpecs)); }; - TableHandleWrapper* percentileBy(double percentile, std::vector columnSpecs) { + TableHandleWrapper* percentileBy(std::vector columnSpecs, double percentile) { return new TableHandleWrapper(internal_tbl_hdl.percentileBy(percentile, columnSpecs)); }; - TableHandleWrapper* countBy(std::string countByColumn, std::vector columnSpecs) { + TableHandleWrapper* countBy(std::vector columnSpecs, std::string countByColumn) { return new TableHandleWrapper(internal_tbl_hdl.countBy(countByColumn, columnSpecs)); }; - TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) { + TableHandleWrapper* headBy(std::vector columnSpecs, int64_t n) { return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); }; - TableHandleWrapper* tailBy(int64_t n, std::vector columnSpecs) { + TableHandleWrapper* tailBy(std::vector columnSpecs, int64_t n) { return new TableHandleWrapper(internal_tbl_hdl.tailBy(n, columnSpecs)); }; From 07a5c8776f12bc920dab957d7285a0b1bacecbf0 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 25 Jul 2023 11:42:49 -0500 Subject: [PATCH 17/73] More unit tests --- R/rdeephaven/NAMESPACE | 57 +- R/rdeephaven/R/table_ops.R | 10 +- .../tests/testthat/test_table_operations.R | 112 ++- R/rdeephaven/man/Client.Rd | 18 - R/rdeephaven/man/ClientOptions.Rd | 18 - R/rdeephaven/man/TableHandle.Rd | 700 ------------------ R/rdeephaven/src/client.cpp | 2 +- 7 files changed, 153 insertions(+), 764 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 78a3fb7e37d..0fc3be040ac 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -1,17 +1,45 @@ # Generated by roxygen2: do not edit by hand +S3method(abs_sum_by,TableHandle) +S3method(agg_by,TableHandle) S3method(as.data.frame,TableHandle) -S3method(nrow,TableHandle) +S3method(avg_by,TableHandle) +S3method(count_by,TableHandle) +S3method(dh_cross_join,TableHandle) +S3method(dh_merge,TableHandle) +S3method(dh_sort,TableHandle) +S3method(dh_ungroup,TableHandle) +S3method(drop_columns,TableHandle) +S3method(exact_join,TableHandle) +S3method(first_by,TableHandle) +S3method(head,TableHandle) +S3method(head_by,TableHandle) +S3method(last_by,TableHandle) +S3method(max_by,TableHandle) +S3method(median_by,TableHandle) +S3method(min_by,TableHandle) +S3method(natural_join,TableHandle) +S3method(percentile_by,TableHandle) S3method(select,TableHandle) +S3method(std_by,TableHandle) +S3method(sum_by,TableHandle) +S3method(tail,TableHandle) +S3method(tail_by,TableHandle) +S3method(update,TableHandle) +S3method(update_view,TableHandle) +S3method(var_by,TableHandle) S3method(view,TableHandle) - +S3method(w_avg_by,TableHandle) +S3method(where,TableHandle) export(Aggregation) export(Client) export(ClientOptions) export(Sorter) export(TableHandle) +export(abs_sum_by) export(agg_abs_sum) export(agg_avg) +export(agg_by) export(agg_count) export(agg_first) export(agg_last) @@ -23,8 +51,33 @@ export(agg_std) export(agg_sum) export(agg_var) export(agg_w_avg) +export(avg_by) +export(count_by) +export(cross_join) +export(dh_cross_join) +export(dh_merge) +export(dh_sort) +export(dh_ungroup) +export(drop_columns) +export(exact_join) +export(first_by) +export(head_by) +export(last_by) +export(max_by) +export(median_by) +export(min_by) +export(natural_join) +export(percentile_by) export(sort_asc) export(sort_desc) +export(std_by) +export(sum_by) +export(tail_by) +export(update_view) +export(var_by) +export(view) +export(w_avg_by) +export(where) import(Rcpp) importFrom(Rcpp,evalCpp) useDynLib(rdeephaven, .registration = TRUE) diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 6522e4c8a3d..9f7a029c3f4 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -144,10 +144,10 @@ avg_by.TableHandle = function(th, columns) { } #' @export -w_avg_by.TableHandle = function(th, weight_column, columns) { +w_avg_by.TableHandle = function(th, columns, weight_column) { verify_string("weight_column", weight_column) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) + return(TableHandle$new(th$internal_table_handle$w_avg_by(columns, weight_column))) } #' @export @@ -191,21 +191,21 @@ percentile_by.TableHandle = function(th, columns, percentile) { count_by.TableHandle = function(th, columns, count_by_column) { verify_string("count_by_column", count_by_column) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) + return(TableHandle$new(th$internal_table_handle$count_by(columns, count_by_column))) } #' @export head_by.TableHandle = function(th, columns, n) { verify_int("n", n) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) + return(TableHandle$new(th$internal_table_handle$head_by(columns, n))) } #' @export tail_by.TableHandle = function(th, columns, n) { verify_int("n", n) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) + return(TableHandle$new(th$internal_table_handle$tail_by(columns, n))) } # JOIN OPERATIONS diff --git a/R/rdeephaven/inst/tests/testthat/test_table_operations.R b/R/rdeephaven/inst/tests/testthat/test_table_operations.R index 545da904dda..528b0997a8b 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_operations.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_operations.R @@ -21,6 +21,11 @@ setup <- function() { Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214)) + + df6 <- data.frame(X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), + Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), + Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), + Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6)) # in order to test TableHandle, we need to have tables on the server that we know everything about. # thus, we have to push these created tables to the server and get TableHandles to each of them. @@ -36,10 +41,11 @@ setup <- function() { th3 <- client$import_table(df3) th4 <- client$import_table(df4) th5 <- client$import_table(df5) + th6 <- client$import_table(df6) return(list("client" = client, - "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5)) + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6)) } ##### TESTING GOOD INPUTS ##### @@ -48,26 +54,26 @@ test_that("select behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - select("string_col") + select(string_col) new_th1 <- data$th1 %>% select("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - select(c("col2", "col3")) + select(col2, col3) new_th2 <- data$th2 %>% select(c("col2", "col3")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% - select(c("X1", "X2")) %>% + select(X1, X2) %>% rename(first_col = X1) new_th3 <- data$th3 %>% select(c("first_col = X1", "X2")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% - select("int_col") %>% + select(int_col) %>% mutate(new_col = int_col + 1, .keep = "none") new_th4 <- data$th4 %>% select("new_col = int_col + 1") @@ -75,7 +81,7 @@ test_that("select behaves as expected", { new_tb5 <- data$df5 %>% mutate(Number3 = Number1 * Number2) %>% - select(c("X", "Number3")) + select(X, Number3) new_th5 <- data$th5 %>% select(c("X", "Number3 = Number1 * Number2")) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) @@ -85,26 +91,26 @@ test_that("view behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - select("string_col") + select(string_col) new_th1 <- data$th1 %>% view("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - select(c("col2", "col3")) + select(col2, col3) new_th2 <- data$th2 %>% view(c("col2", "col3")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% - select(c("X1", "X2")) %>% + select(X1, X2) %>% rename(first_col = X1) new_th3 <- data$th3 %>% view(c("first_col = X1", "X2")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% - select("int_col") %>% + select(int_col) %>% mutate(new_col = int_col + 1, .keep = "none") new_th4 <- data$th4 %>% view("new_col = int_col + 1") @@ -112,7 +118,7 @@ test_that("view behaves as expected", { new_tb5 <- data$df5 %>% mutate(Number3 = Number1 * Number2) %>% - select(c("X", "Number3")) + select(X, Number3) new_th5 <- data$th5 %>% view(c("X", "Number3 = Number1 * Number2")) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) @@ -190,13 +196,13 @@ test_that("drop_columns behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - select(-"string_col") + select(-string_col) new_th1 <- data$th1 %>% drop_columns("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - select(-c("col1", "col2")) + select(-c(col1, col2)) new_th2 <- data$th2 %>% drop_columns(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) @@ -418,6 +424,11 @@ test_that("avg_by behaves as expected", { expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) +# I think that the current behavior of wAvgBy() is wrong and needs to be updated +test_that("w_avg_by behaves as expected", { + data <- setup() +}) + test_that("first_by behaves as expected", { data <- setup() @@ -486,26 +497,87 @@ test_that("median_by behaves as expected", { test_that("percentile_by behaves as expected", { data <- setup() + + # There is not a clean analog to `percentile_by` in dplyr, so we construct + # these data frames directly. + + new_df1 <- data.frame(X = c("A", "B", "C"), + Number1 = c(50, -44, -70), + Number2 = c(-50, 76, 130)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + percentile_by("X", 0.4) + expect_equal(as.data.frame(new_th1), new_df1) + + new_df2 <- data.frame(X = c("A", "B", "A", "C", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "O", "M"), + Number1 = c(50, -44, 49, 11, -66, 29, -70), + Number2 = c(-55, 76, 20, 130, 137, 73, 214)) + new_th2 <- data$th5 %>% + percentile_by(c("X", "Y"), 0.4) + expect_equal(as.data.frame(new_th2), new_df2) + }) test_that("count_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + count(X) + new_th1 <- data$th5 %>% + count_by("X", "n") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + count(X, Y) + new_th2 <- data$th5 %>% + count_by(c("X", "Y"), "n") %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -test_that("w_avg_by behaves as expected", { - data <- setup() +test_that("head_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 %>% + group_by(X) %>% + slice_head(n=2) + new_th1 <- data$th5 %>% + head_by("X", 2) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + slice_head(n=2) + new_th2 <- data$th5 %>% + head_by(c("X", "Y"), 2) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("tail_by behaves as expected", { data <- setup() -}) - -test_that("head_by behaves as expected", { - data <- setup() + + new_tb1 <- data$df5 %>% + group_by(X) %>% + slice_tail(n=2) + new_th1 <- data$th5 %>% + tail_by("X", 2) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + slice_tail(n=2) + new_th2 <- data$th5 %>% + tail_by(c("X", "Y"), 2) %>% + dh_sort(c(sort_asc("X"), sort_asc("Y"))) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("cross_join behaves as expected", { data <- setup() + + }) test_that("natural_join behaves as expected", { diff --git a/R/rdeephaven/man/Client.Rd b/R/rdeephaven/man/Client.Rd index 33b67a6a68a..296453084ae 100644 --- a/R/rdeephaven/man/Client.Rd +++ b/R/rdeephaven/man/Client.Rd @@ -31,7 +31,6 @@ client$run_script("print([i for i in range(10)])") \item \href{#method-Client-open_table}{\code{Client$open_table()}} \item \href{#method-Client-import_table}{\code{Client$import_table()}} \item \href{#method-Client-run_script}{\code{Client$run_script()}} -\item \href{#method-Client-clone}{\code{Client$clone()}} } } \if{html}{\out{
}} @@ -113,21 +112,4 @@ Runs a script on the server. The script must be in the language that the server \if{html}{\out{}} } } -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Client-clone}{}}} -\subsection{Method \code{clone()}}{ -The objects of this class are cloneable with this method. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Client$clone(deep = FALSE)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{deep}}{Whether to make a deep clone.} -} -\if{html}{\out{
}} -} -} } diff --git a/R/rdeephaven/man/ClientOptions.Rd b/R/rdeephaven/man/ClientOptions.Rd index 2e49dec7cb3..f7e00204ddf 100644 --- a/R/rdeephaven/man/ClientOptions.Rd +++ b/R/rdeephaven/man/ClientOptions.Rd @@ -46,7 +46,6 @@ client <- Client$new(target="url/to/secure/server", client_options=client_option \item \href{#method-ClientOptions-add_int_option}{\code{ClientOptions$add_int_option()}} \item \href{#method-ClientOptions-add_string_option}{\code{ClientOptions$add_string_option()}} \item \href{#method-ClientOptions-add_extra_header}{\code{ClientOptions$add_extra_header()}} -\item \href{#method-ClientOptions-clone}{\code{ClientOptions$clone()}} } } \if{html}{\out{
}} @@ -198,21 +197,4 @@ Adds an extra header with a constant name and value to be sent with every outgoi \if{html}{\out{}} } } -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-clone}{}}} -\subsection{Method \code{clone()}}{ -The objects of this class are cloneable with this method. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$clone(deep = FALSE)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{deep}}{Whether to make a deep clone.} -} -\if{html}{\out{
}} -} -} } diff --git a/R/rdeephaven/man/TableHandle.Rd b/R/rdeephaven/man/TableHandle.Rd index c353673a401..888b6b8e182 100644 --- a/R/rdeephaven/man/TableHandle.Rd +++ b/R/rdeephaven/man/TableHandle.Rd @@ -39,37 +39,6 @@ new_table_handle2$bind_to_variable("new_table") \item \href{#method-TableHandle-to_arrow_table}{\code{TableHandle$to_arrow_table()}} \item \href{#method-TableHandle-to_tibble}{\code{TableHandle$to_tibble()}} \item \href{#method-TableHandle-to_data_frame}{\code{TableHandle$to_data_frame()}} -\item \href{#method-TableHandle-select}{\code{TableHandle$select()}} -\item \href{#method-TableHandle-view}{\code{TableHandle$view()}} -\item \href{#method-TableHandle-update}{\code{TableHandle$update()}} -\item \href{#method-TableHandle-update_view}{\code{TableHandle$update_view()}} -\item \href{#method-TableHandle-drop_columns}{\code{TableHandle$drop_columns()}} -\item \href{#method-TableHandle-where}{\code{TableHandle$where()}} -\item \href{#method-TableHandle-agg_by}{\code{TableHandle$agg_by()}} -\item \href{#method-TableHandle-min_by}{\code{TableHandle$min_by()}} -\item \href{#method-TableHandle-max_by}{\code{TableHandle$max_by()}} -\item \href{#method-TableHandle-sum_by}{\code{TableHandle$sum_by()}} -\item \href{#method-TableHandle-abs_sum_by}{\code{TableHandle$abs_sum_by()}} -\item \href{#method-TableHandle-avg_by}{\code{TableHandle$avg_by()}} -\item \href{#method-TableHandle-w_avg_by}{\code{TableHandle$w_avg_by()}} -\item \href{#method-TableHandle-var_by}{\code{TableHandle$var_by()}} -\item \href{#method-TableHandle-std_by}{\code{TableHandle$std_by()}} -\item \href{#method-TableHandle-first_by}{\code{TableHandle$first_by()}} -\item \href{#method-TableHandle-last_by}{\code{TableHandle$last_by()}} -\item \href{#method-TableHandle-median_by}{\code{TableHandle$median_by()}} -\item \href{#method-TableHandle-percentile_by}{\code{TableHandle$percentile_by()}} -\item \href{#method-TableHandle-count_by}{\code{TableHandle$count_by()}} -\item \href{#method-TableHandle-head_by}{\code{TableHandle$head_by()}} -\item \href{#method-TableHandle-tail_by}{\code{TableHandle$tail_by()}} -\item \href{#method-TableHandle-cross_join}{\code{TableHandle$cross_join()}} -\item \href{#method-TableHandle-natural_join}{\code{TableHandle$natural_join()}} -\item \href{#method-TableHandle-exact_join}{\code{TableHandle$exact_join()}} -\item \href{#method-TableHandle-head}{\code{TableHandle$head()}} -\item \href{#method-TableHandle-tail}{\code{TableHandle$tail()}} -\item \href{#method-TableHandle-ungroup}{\code{TableHandle$ungroup()}} -\item \href{#method-TableHandle-sort}{\code{TableHandle$sort()}} -\item \href{#method-TableHandle-merge}{\code{TableHandle$merge()}} -\item \href{#method-TableHandle-clone}{\code{TableHandle$clone()}} } } \if{html}{\out{
}} @@ -177,673 +146,4 @@ Imports the table referenced by this TableHandle into an R Data Frame. A Data Frame containing the data from the table referenced by this TableHandle. } } -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-select}{}}} -\subsection{Method \code{select()}}{ -Select columns from a table. The columns can be column names or formulas like -"NewCol = A + 12". See the Deephaven documentation for the difference between "select" and "view". -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$select(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{The columns to select.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-view}{}}} -\subsection{Method \code{view()}}{ -View columns from a table. The columns can be column names or formulas like -"NewCol = A + 12". See the Deephaven documentation for the difference between select() and view(). -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$view(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{The columns to view.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-update}{}}} -\subsection{Method \code{update()}}{ -Creates a new table from this table, but including the additional specified columns. -See the Deephaven documentation for the difference between update() and updateView(). -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$update(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{The columns to add. For example, {"X = A + 5", "Y = X * 2"}.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-update_view}{}}} -\subsection{Method \code{update_view()}}{ -Creates a new view from this table, but including the additional specified columns. -See the Deephaven documentation for the difference between update() and updateView(). -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$update_view(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{The columns to add. For example, {"X = A + 5", "Y = X * 2"}.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-drop_columns}{}}} -\subsection{Method \code{drop_columns()}}{ -Creates a new table from this table where the specified columns have been excluded. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$drop_columns(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{The columns to exclude.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-where}{}}} -\subsection{Method \code{where()}}{ -Creates a new table from this table, filtered by condition. Consult the Deephaven -documentation for more information about valid conditions. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$where(condition)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{condition}}{A Deephaven boolean expression such as "Price > 100" or "Col3 == Col1 * Col2".} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-agg_by}{}}} -\subsection{Method \code{agg_by()}}{ -Creates a new table from this table with one or more aggregations applied to the specified columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$agg_by(aggregations)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{aggregations}}{Deephaven Aggregations to apply to this table.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-min_by}{}}} -\subsection{Method \code{min_by()}}{ -Creates a new table from this table, grouped by columns, with the "min" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$min_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-max_by}{}}} -\subsection{Method \code{max_by()}}{ -Creates a new table from this table, grouped by columns, with the "max" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$max_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-sum_by}{}}} -\subsection{Method \code{sum_by()}}{ -Creates a new table from this table, grouped by columns, with the "sum" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$sum_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-abs_sum_by}{}}} -\subsection{Method \code{abs_sum_by()}}{ -Creates a new table from this table, grouped by columns, with the "absSum" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$abs_sum_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-avg_by}{}}} -\subsection{Method \code{avg_by()}}{ -Creates a new table from this table, grouped by columns, with the "avg" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$avg_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-w_avg_by}{}}} -\subsection{Method \code{w_avg_by()}}{ -Creates a new table from this table, grouped by columns, having a new column named by -`weightColumn` containing the weighted average of each group. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$w_avg_by(weight_column, columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{weight_column}}{Name of the output column.} - -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-var_by}{}}} -\subsection{Method \code{var_by()}}{ -Creates a new table from this table, grouped by columns, with the "var" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$var_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-std_by}{}}} -\subsection{Method \code{std_by()}}{ -Creates a new table from this table, grouped by columns, with the "std" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$std_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-first_by}{}}} -\subsection{Method \code{first_by()}}{ -Creates a new table from this table, grouped by columns, with the "first" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$first_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-last_by}{}}} -\subsection{Method \code{last_by()}}{ -Creates a new table from this table, grouped by columns, with the "last" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$last_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-median_by}{}}} -\subsection{Method \code{median_by()}}{ -Creates a new table from this table, grouped by columns, with the "median" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$median_by(columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-percentile_by}{}}} -\subsection{Method \code{percentile_by()}}{ -Creates a new table from this table, grouped by columns, with the "percentile" aggregate operation -applied to the remaining columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$percentile_by(percentile, columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{percentile}}{The designated percentile} - -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-count_by}{}}} -\subsection{Method \code{count_by()}}{ -Creates a new table from this table, grouped by columns, having a new column named by -`countByColumn` containing the size of each group. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$count_by(count_by_column, columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{count_by_column}}{Name of the output column.} - -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-head_by}{}}} -\subsection{Method \code{head_by()}}{ -Creates a new table from this table, grouped by columns, containing the first `n` rows of -each group. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$head_by(n, columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{n}}{Number of rows} - -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-tail_by}{}}} -\subsection{Method \code{tail_by()}}{ -Creates a new table from this table, grouped by columns, containing the last `n` rows of -each group. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$tail_by(n, columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{n}}{Number of rows} - -\item{\code{columns}}{Columns to group by.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-cross_join}{}}} -\subsection{Method \code{cross_join()}}{ -Creates a new table by cross joining this table with `rightSide`. The tables are joined by -the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally -renamed by `columnsToAdd`. Example: -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$cross_join(right_side, columns_to_match, columns_to_add)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{right_side}}{The table to join with this table} - -\item{\code{columns_to_match}}{The columns to join on} - -\item{\code{columns_to_add}}{The columns from the right side to add, and possibly rename.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-natural_join}{}}} -\subsection{Method \code{natural_join()}}{ -Creates a new table by natural joining this table with `rightSide`. The tables are joined by -the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally -renamed by `columnsToAdd`. Example: -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$natural_join(right_side, columns_to_match, columns_to_add)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{right_side}}{The table to join with this table} - -\item{\code{columns_to_match}}{The columns to join on} - -\item{\code{columns_to_add}}{The columns from the right side to add, and possibly rename.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-exact_join}{}}} -\subsection{Method \code{exact_join()}}{ -Creates a new table by exact joining this table with `rightSide`. The tables are joined by -the columns in `columnsToMatch`, and columns from `rightSide` are brought in and optionally -renamed by `columnsToAdd`. Example: -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$exact_join(right_side, columns_to_match, columns_to_add)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{right_side}}{The table to join with this table} - -\item{\code{columns_to_match}}{The columns to join on} - -\item{\code{columns_to_add}}{The columns from the right side to add, and possibly rename.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-head}{}}} -\subsection{Method \code{head()}}{ -Creates a new table from this table containing the first `n` rows of this table. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$head(n)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{n}}{Number of rows} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-tail}{}}} -\subsection{Method \code{tail()}}{ -Creates a new table from this table containing the last `n` rows of this table. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$tail(n)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{n}}{Number of rows} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-ungroup}{}}} -\subsection{Method \code{ungroup()}}{ -Creates a new table from this table with the column array data ungrouped. This is the inverse -of the by() const operation. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$ungroup(null_fill, group_by_columns)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{group_by_columns}}{Columns to ungroup.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-sort}{}}} -\subsection{Method \code{sort()}}{ -Creates a new table from this table, sorted by sortPairs. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$sort(sorters)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{sorters}}{A vector of Deephaven Sorter objects (either sort.asc or sort.desc) describing the sort. -Each Sorter accepts a column to sort, and whether the sort should consider to the value's regular or -absolute value when doing comparisons.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-merge}{}}} -\subsection{Method \code{merge()}}{ -Creates a new table by merging `sources` together. The tables are essentially stacked on top -of each other. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$merge(key_column, sources)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{sources}}{The tables to merge.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -A TableHandle referencing the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-clone}{}}} -\subsection{Method \code{clone()}}{ -The objects of this class are cloneable with this method. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$clone(deep = FALSE)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{deep}}{Whether to make a deep clone.} -} -\if{html}{\out{
}} -} -} } diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 54533ce8c79..2221632b7e1 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -205,7 +205,7 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.avgBy(columnSpecs)); }; - TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) { + TableHandleWrapper* wAvgBy(std::vector columnSpecs, std::string weightColumn) { return new TableHandleWrapper(internal_tbl_hdl.wAvgBy(weightColumn, columnSpecs)); }; From 8c0eb9290c8a4fc623363b7a8f3adbf6758d03d3 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 25 Jul 2023 15:11:04 -0500 Subject: [PATCH 18/73] Simplify sorting API, more unit tests --- R/rdeephaven/NAMESPACE | 23 +--- R/rdeephaven/R/helper_functions.R | 14 ++- R/rdeephaven/R/sort_wrapper.R | 32 ----- R/rdeephaven/R/table_ops.R | 109 +++++------------- .../inst/tests/testthat/test_sorter_wrapper.R | 45 -------- .../tests/testthat/test_table_operations.R | 39 +++---- R/rdeephaven/src/client.cpp | 60 ++++------ 7 files changed, 84 insertions(+), 238 deletions(-) delete mode 100644 R/rdeephaven/R/sort_wrapper.R delete mode 100644 R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 0fc3be040ac..d9390a40d9f 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -1,35 +1,15 @@ # Generated by roxygen2: do not edit by hand -S3method(abs_sum_by,TableHandle) -S3method(agg_by,TableHandle) S3method(as.data.frame,TableHandle) -S3method(avg_by,TableHandle) -S3method(count_by,TableHandle) -S3method(dh_cross_join,TableHandle) S3method(dh_merge,TableHandle) -S3method(dh_sort,TableHandle) S3method(dh_ungroup,TableHandle) S3method(drop_columns,TableHandle) -S3method(exact_join,TableHandle) -S3method(first_by,TableHandle) S3method(head,TableHandle) -S3method(head_by,TableHandle) -S3method(last_by,TableHandle) -S3method(max_by,TableHandle) -S3method(median_by,TableHandle) -S3method(min_by,TableHandle) -S3method(natural_join,TableHandle) -S3method(percentile_by,TableHandle) S3method(select,TableHandle) -S3method(std_by,TableHandle) -S3method(sum_by,TableHandle) S3method(tail,TableHandle) -S3method(tail_by,TableHandle) S3method(update,TableHandle) S3method(update_view,TableHandle) -S3method(var_by,TableHandle) S3method(view,TableHandle) -S3method(w_avg_by,TableHandle) S3method(where,TableHandle) export(Aggregation) export(Client) @@ -54,9 +34,7 @@ export(agg_w_avg) export(avg_by) export(count_by) export(cross_join) -export(dh_cross_join) export(dh_merge) -export(dh_sort) export(dh_ungroup) export(drop_columns) export(exact_join) @@ -69,6 +47,7 @@ export(min_by) export(natural_join) export(percentile_by) export(sort_asc) +export(sort_by) export(sort_desc) export(std_by) export(sum_by) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 988800afdfb..c2d7bf04e62 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -1,6 +1,4 @@ -first_class = function(arg) { - return(class(arg)[[1]]) -} +first_class <- function(arg) class(arg)[[1]] verify_internal_type <- function(desired_type, arg_name, candidate) { if ((first_class(candidate) == "list") && (any(lapply(candidate, first_class) != desired_type))) { @@ -20,6 +18,12 @@ verify_bool <- function(arg_name, bool_candidate) { } } +verify_bool_vector <- function(arg_name, bool_candidate) { + if (first_class(bool_candidate) != "logical") { + stop(paste0("'", arg_name, "' must be passed as a boolean or a vector of booleans. Got an object of class ", first_class(bool_candidate), " instead.")) + } +} + verify_int <- function(arg_name, int_candidate) { if (class(int_candidate)[[1]] != "numeric") { stop(paste0("'", arg_name, "' must be an integer. Got an object of class ", first_class(int_candidate), " instead.")) @@ -60,10 +64,10 @@ verify_string_vector <- function(arg_name, string_vector_candidate) { } } -strip_r6_wrapping_from_aggregation = function(r6_aggregation) { +strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { return(r6_aggregation$internal_aggregation) } -strip_r6_wrapping_from_sorter = function(r6_sorter) { +strip_r6_wrapping_from_sorter <- function(r6_sorter) { return(r6_sorter$internal_sorter) } \ No newline at end of file diff --git a/R/rdeephaven/R/sort_wrapper.R b/R/rdeephaven/R/sort_wrapper.R deleted file mode 100644 index 7ae10f40e03..00000000000 --- a/R/rdeephaven/R/sort_wrapper.R +++ /dev/null @@ -1,32 +0,0 @@ -#' @export -Sorter <- R6Class("Sorter", cloneable = FALSE, - public = list( - - #' @description - #' Create a Sorter instance. - initialize = function(sort_pair) { - if (class(sort_pair) != "Rcpp_INTERNAL_SortPair") { - stop("'sort_pair' should be an internal Deephaven SortPair. If you're seeing this,\n you are trying to call the constructor of a Sorter directly, which is not advised.\n Please use one of the provided sorting functions instead.") - } - self$internal_sorter <- sort_pair - }, - - internal_sorter = NULL - ) -) - -### All of the functions below return an instance of the above class - -#' @export -sort_asc <- function(column, abs=FALSE) { - verify_string("column", column) - verify_bool("abs", abs) - return(Sorter$new(INTERNAL_sort_asc(column, abs))) -} - -#' @export -sort_desc <- function(column, abs=FALSE) { - verify_string("column", column) - verify_bool("abs", abs) - return(Sorter$new(INTERNAL_sort_desc(column, abs))) -} \ No newline at end of file diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 9f7a029c3f4..a68ce9cc801 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -11,56 +11,11 @@ drop_columns <- function(x, ...) {UseMethod("drop_columns", x)} #' @export where <- function(x, ...) {UseMethod("where", x)} -#' @export -abs_sum_by <- function(x, ...) {UseMethod("abs_sum_by", x)} -#' @export -agg_by <- function(x, ...) {UseMethod("agg_by", x)} -#' @export -avg_by <- function(x, ...) {UseMethod("avg_by", x)} -#' @export -count_by <- function(x, ...) {UseMethod("count_by", x)} -#' @export -first_by <- function(x, ...) {UseMethod("first_by", x)} -#' @export -head_by <- function(x, ...) {UseMethod("head_by", x)} -#' @export -last_by <- function(x, ...) {UseMethod("last_by", x)} -#' @export -max_by <- function(x, ...) {UseMethod("max_by", x)} -#' @export -median_by <- function(x, ...) {UseMethod("median_by", x)} -#' @export -min_by <- function(x, ...) {UseMethod("min_by", x)} -#' @export -percentile_by <- function(x, ...) {UseMethod("percentile_by", x)} -#' @export -std_by <- function(x, ...) {UseMethod("std_by", x)} -#' @export -sum_by <- function(x, ...) {UseMethod("sum_by", x)} -#' @export -tail_by <- function(x, ...) {UseMethod("tail_by", x)} -#' @export -var_by <- function(x, ...) {UseMethod("var_by", x)} -#' @export -w_avg_by <- function(x, ...) {UseMethod("w_avg_by", x)} - -#' @export -cross_join <- function(x, ...) {UseMethod("cross_join", x)} -#' @export -natural_join <- function(x, ...) {UseMethod("natural_join", x)} -#' @export -exact_join <- function(x, ...) {UseMethod("exact_join", x)} - # TODO: figure this shit out #' @export dh_ungroup <- function(x, ...) {UseMethod("dh_ungroup", x)} #' @export -dh_sort <- function(x, ...) {UseMethod("dh_sort", x)} -#' @export dh_merge <- function(x, ...) {UseMethod("dh_merge", x)} -#' @export -dh_cross_join <- function(x, ...) {UseMethod("dh_cross_join", x)} - ### S3 METHODS (implemented generics) @@ -95,7 +50,7 @@ drop_columns.TableHandle <- function(th, columns) { } #' @export -where.TableHandle = function(th, condition) { +where.TableHandle <- function(th, condition) { verify_string("condition", condition) return(TableHandle$new(th$internal_table_handle$where(condition))) } @@ -103,9 +58,9 @@ where.TableHandle = function(th, condition) { # AGGREGATION OPERATIONS #' @export -agg_by.TableHandle = function(th, aggregations) { +agg_by <- function(th, aggregations) { verify_internal_type("Aggregation", "aggregations", aggregations) - if ((first_class(aggregations) != "list") && (first_class(aggregations) == "Aggregation")) { + if (length(aggregations) == 1) { aggregations = c(aggregations) } unwrapped_aggregations = lapply(aggregations, strip_r6_wrapping_from_aggregation) @@ -114,95 +69,95 @@ agg_by.TableHandle = function(th, aggregations) { } #' @export -min_by.TableHandle = function(th, columns) { +min_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$min_by(columns))) } #' @export -max_by.TableHandle = function(th, columns) { +max_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$max_by(columns))) } #' @export -sum_by.TableHandle = function(th, columns) { +sum_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$sum_by(columns))) } #' @export -abs_sum_by.TableHandle = function(th, columns) { +abs_sum_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) } #' @export -avg_by.TableHandle = function(th, columns) { +avg_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$avg_by(columns))) } #' @export -w_avg_by.TableHandle = function(th, columns, weight_column) { +w_avg_by <- function(th, columns, weight_column) { verify_string("weight_column", weight_column) verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$w_avg_by(columns, weight_column))) } #' @export -var_by.TableHandle = function(th, columns) { +var_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$var_by(columns))) } #' @export -std_by.TableHandle = function(th, columns) { +std_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$std_by(columns))) } #' @export -first_by.TableHandle = function(th, columns) { +first_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$first_by(columns))) } #' @export -last_by.TableHandle = function(th, columns) { +last_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$last_by(columns))) } #' @export -median_by.TableHandle = function(th, columns) { +median_by <- function(th, columns) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$median_by(columns))) } #' @export -percentile_by.TableHandle = function(th, columns, percentile) { +percentile_by <- function(th, columns, percentile) { verify_string_vector("columns", columns) verify_proportion("percentile", percentile) return(TableHandle$new(th$internal_table_handle$percentile_by(columns, percentile))) } #' @export -count_by.TableHandle = function(th, columns, count_by_column) { +count_by <- function(th, columns, count_by_column) { verify_string("count_by_column", count_by_column) verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$count_by(columns, count_by_column))) } #' @export -head_by.TableHandle = function(th, columns, n) { +head_by <- function(th, columns, n) { verify_int("n", n) verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$head_by(columns, n))) } #' @export -tail_by.TableHandle = function(th, columns, n) { +tail_by <- function(th, columns, n) { verify_int("n", n) verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$tail_by(columns, n))) @@ -211,7 +166,7 @@ tail_by.TableHandle = function(th, columns, n) { # JOIN OPERATIONS #' @export -dh_cross_join.TableHandle = function(th, right_side, columns_to_match, columns_to_add) { +cross_join <- function(th, right_side, columns_to_match, columns_to_add) { verify_string_vector("columns_to_match", columns_to_match) verify_string_vector("columns_to_add", columns_to_add) return(TableHandle$new(th$internal_table_handle$cross_join(right_side$internal_table_handle, @@ -219,7 +174,7 @@ dh_cross_join.TableHandle = function(th, right_side, columns_to_match, columns_t } #' @export -natural_join.TableHandle = function(th, right_side, columns_to_match, columns_to_add) { +natural_join <- function(th, right_side, columns_to_match, columns_to_add) { verify_string_vector("columns_to_match", columns_to_match) verify_string_vector("columns_to_add", columns_to_add) return(TableHandle$new(th$internal_table_handle$natural_join(right_side$internal_table_handle, @@ -227,7 +182,7 @@ natural_join.TableHandle = function(th, right_side, columns_to_match, columns_to } #' @export -exact_join.TableHandle = function(th, right_side, columns_to_match, columns_to_add) { +exact_join <- function(th, right_side, columns_to_match, columns_to_add) { verify_string_vector("columns_to_match", columns_to_match) verify_string_vector("columns_to_add", columns_to_add) return(TableHandle$new(th$internal_table_handle$exact_join(right_side$internal_table_handle, @@ -237,35 +192,35 @@ exact_join.TableHandle = function(th, right_side, columns_to_match, columns_to_a # MISC OPERATIONS #' @export -head.TableHandle = function(th, n) { +head.TableHandle <- function(th, n) { verify_int("n", n) return(TableHandle$new(th$internal_table_handle$head(n))) } #' @export -tail.TableHandle = function(th, n) { +tail.TableHandle <- function(th, n) { verify_int("n", n) return(TableHandle$new(th$internal_table_handle$tail(n))) } #' @export -dh_ungroup.TableHandle = function(th, null_fill, group_by_columns) { - verify_string_vector(group_by_columns, "group_by_columns") +dh_ungroup.TableHandle <- function(th, null_fill, group_by_columns) { + verify_string_vector("group_by_columns", group_by_columns) return(TableHandle$new(th$internal_table_handle$ungroup(null_fill, group_by_columns))) } #' @export -dh_sort.TableHandle = function(th, sorters) { - verify_internal_type("Sorter", "sorters", sorters) - if ((first_class(sorters) != "list") && (first_class(sorters) == "Sorter")) { - sorters = c(sorters) +sort_by <- function(th, columns, descending = FALSE) { + verify_string_vector("columns", columns) + verify_bool_vector("descending", descending) + if ((length(descending) > 1) && length(descending) != length(columns)) { + stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) } - unwrapped_sorters = lapply(sorters, strip_r6_wrapping_from_sorter) - return(TableHandle$new(th$internal_table_handle$sort(unwrapped_sorters))) + return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) } #' @export -dh_merge.TableHandle = function(th, key_column, sources) { +dh_merge.TableHandle <- function(th, key_column, sources) { verify_string("key_column", key_column) return(TableHandle$new(th$internal_table_handle$merge(key_column, sources))) } \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R deleted file mode 100644 index 4280fa30b96..00000000000 --- a/R/rdeephaven/inst/tests/testthat/test_sorter_wrapper.R +++ /dev/null @@ -1,45 +0,0 @@ -library(testthat) -library(rdeephaven) - -##### TESTING BAD INPUTS ##### - -test_that("trying to instantiate a Sorter fails nicely", { - expect_error(Sorter$new("hello"), - "'sort_pair' should be an internal Deephaven SortPair. If you're seeing this,\n you are trying to call the constructor of a Sorter directly, which is not advised.\n Please use one of the provided sorting functions instead.") -}) - -test_that("sort_asc fails when 'column' is a bad type", { - expect_error(sort_asc(5), - "'column' must be passed as a single string. Got an object of class numeric instead.") - expect_error(sort_asc(TRUE), - "'column' must be passed as a single string. Got an object of class logical instead.") - expect_error(sort_asc(c("a", "b", "c", "d")), - "'column' must be passed as a single string. Got a character vector of length 4 instead.") -}) - -test_that("sort_asc fails when 'abs' is a bad type", { - expect_error(sort_asc("string", abs=1), - "'abs' must be passed as a single boolean. Got an object of class numeric instead.") - expect_error(sort_asc("string", abs="hello!"), - "'abs' must be passed as a single boolean. Got an object of class character instead.") - expect_error(sort_asc("string", abs=c(TRUE, TRUE, FALSE)), - "'abs' must be passed as a single boolean. Got a boolean vector of length 3 instead.") -}) - -test_that("sort_desc fails when 'column' is a bad type", { - expect_error(sort_desc(5), - "'column' must be passed as a single string. Got an object of class numeric instead.") - expect_error(sort_desc(TRUE), - "'column' must be passed as a single string. Got an object of class logical instead.") - expect_error(sort_desc(c("a", "b", "c", "d")), - "'column' must be passed as a single string. Got a character vector of length 4 instead.") -}) - -test_that("sort_desc fails when 'abs' is a bad type", { - expect_error(sort_desc("string", abs=1), - "'abs' must be passed as a single boolean. Got an object of class numeric instead.") - expect_error(sort_desc("string", abs="hello!"), - "'abs' must be passed as a single boolean. Got an object of class character instead.") - expect_error(sort_desc("string", abs=c(TRUE, TRUE, FALSE)), - "'abs' must be passed as a single boolean. Got a boolean vector of length 3 instead.") -}) \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_table_operations.R b/R/rdeephaven/inst/tests/testthat/test_table_operations.R index 528b0997a8b..e16730e9aac 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_operations.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_operations.R @@ -261,7 +261,7 @@ test_that("min_by behaves as expected", { new_th3 <- data$th3 %>% update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% min_by(c("bool_col1", "bool_col2")) %>% - dh_sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same + sort_by(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -270,7 +270,7 @@ test_that("min_by behaves as expected", { arrange(bool_col) new_th4 <- data$th4 %>% min_by("bool_col") %>% - dh_sort(sort_asc("bool_col")) + sort_by("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) }) @@ -299,7 +299,7 @@ test_that("max_by behaves as expected", { new_th3 <- data$th3 %>% update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% max_by(c("bool_col1", "bool_col2")) %>% - dh_sort(c(sort_asc("bool_col1"), sort_asc("bool_col2"))) # need to sort because resulting row orders are not the same + max_by(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -308,7 +308,7 @@ test_that("max_by behaves as expected", { arrange(bool_col) new_th4 <- data$th4 %>% max_by("bool_col") %>% - dh_sort(sort_asc("bool_col")) + sort_by("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) }) @@ -330,7 +330,7 @@ test_that("sum_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% sum_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -354,7 +354,7 @@ test_that("abs_sum_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% abs_sum_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -376,7 +376,7 @@ test_that("var_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% var_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -398,7 +398,7 @@ test_that("std_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% std_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -420,11 +420,11 @@ test_that("avg_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% avg_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -# I think that the current behavior of wAvgBy() is wrong and needs to be updated +# TODO: I think that the current behavior of wAvgBy() is wrong and needs to be updated test_that("w_avg_by behaves as expected", { data <- setup() }) @@ -447,7 +447,7 @@ test_that("first_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% first_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -469,7 +469,7 @@ test_that("last_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% last_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -491,15 +491,15 @@ test_that("median_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% median_by(c("X", "Y")) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("percentile_by behaves as expected", { data <- setup() - # There is not a clean analog to `percentile_by` in dplyr, so we construct - # these data frames directly. + # There is not a clean analog to `percentile_by` in dplyr, + # so we construct these data frames directly. new_df1 <- data.frame(X = c("A", "B", "C"), Number1 = c(50, -44, -70), @@ -532,7 +532,7 @@ test_that("count_by behaves as expected", { count(X, Y) new_th2 <- data$th5 %>% count_by(c("X", "Y"), "n") %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -551,7 +551,7 @@ test_that("head_by behaves as expected", { slice_head(n=2) new_th2 <- data$th5 %>% head_by(c("X", "Y"), 2) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -570,14 +570,13 @@ test_that("tail_by behaves as expected", { slice_tail(n=2) new_th2 <- data$th5 %>% tail_by(c("X", "Y"), 2) %>% - dh_sort(c(sort_asc("X"), sort_asc("Y"))) + sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) +# TODO: Our definition of a cross join is significantly different from dplyr test_that("cross_join behaves as expected", { data <- setup() - - }) test_that("natural_join behaves as expected", { diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 2221632b7e1..5063c854b15 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -107,40 +107,6 @@ AggregateWrapper* INTERNAL_count(std::string columnSpec) { } -class SortPairWrapper { -public: - SortPairWrapper(); - SortPairWrapper(deephaven::client::SortPair sort_pair) : - internal_sorter(std::move(sort_pair)) {} -private: - deephaven::client::SortPair internal_sorter; - friend TableHandleWrapper; - friend std::vector convertRcppListToVectorOfTypeSortPair(Rcpp::List rcpp_list); -}; - -// ######################### conversion function for the above class -std::vector convertRcppListToVectorOfTypeSortPair(Rcpp::List rcpp_list) { - std::vector converted_list; - converted_list.reserve(rcpp_list.size()); - - for(int i = 0; i < rcpp_list.size(); i++) { - Rcpp::Environment rcpp_list_element = rcpp_list[i]; - Rcpp::XPtr xptr(rcpp_list_element.get(".pointer")); - deephaven::client::SortPair internal_sorter = xptr->internal_sorter; - converted_list.push_back(internal_sorter); - } - return converted_list; -} - -SortPairWrapper* INTERNAL_sortAsc(std::string column, bool abs) { - return new SortPairWrapper(deephaven::client::SortPair::ascending(column, abs)); -} - -SortPairWrapper* INTERNAL_sortDesc(std::string column, bool abs) { - return new SortPairWrapper(deephaven::client::SortPair::descending(column, abs)); -} - - class TableHandleWrapper { public: TableHandleWrapper(deephaven::client::TableHandle ref_table) : @@ -278,9 +244,29 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, converted_sources)); }; - TableHandleWrapper* sort(Rcpp::List sortPairs) { - std::vector converted_sort_pairs = convertRcppListToVectorOfTypeSortPair(sortPairs); - return new TableHandleWrapper(internal_tbl_hdl.sort(converted_sort_pairs)); + TableHandleWrapper* sort(std::vector columnSpecs, std::vector descending) { + std::vector sort_pairs; + sort_pairs.reserve(columnSpecs.size()); + if (descending.size() == 1) { + if (descending[0] == false) { + for(int i = 0; i < columnSpecs.size(); i++) { + sort_pairs.push_back(deephaven::client::SortPair::ascending(columnSpecs[i], false)); + } + } else { + for(int i = 0; i < columnSpecs.size(); i++) { + sort_pairs.push_back(deephaven::client::SortPair::descending(columnSpecs[i], false)); + } + } + } else { + for(int i = 0; i < columnSpecs.size(); i++) { + if (descending[i] == false) { + sort_pairs.push_back(deephaven::client::SortPair::ascending(columnSpecs[i], false)); + } else { + sort_pairs.push_back(deephaven::client::SortPair::descending(columnSpecs[i], false)); + } + } + } + return new TableHandleWrapper(internal_tbl_hdl.sort(sort_pairs)); }; /** From 09b2f8355338f29d7729cca7b8899ae32cd7a5e2 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 25 Jul 2023 15:55:40 -0500 Subject: [PATCH 19/73] Reorder table operations logically, connect ClientWrapper to newly exposed methods in C++ --- R/rdeephaven/R/client_wrapper.R | 22 ++++++++ R/rdeephaven/R/table_ops.R | 76 +++++++++++++-------------- R/rdeephaven/src/client.cpp | 93 +++++++++++++++------------------ 3 files changed, 102 insertions(+), 89 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 3586aea994d..68b274867f7 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -52,6 +52,28 @@ Client <- R6Class("Client", cloneable = FALSE, return(TableHandle$new(private$internal_client$open_table(name))) }, + #' @description + #' Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. + #' @param size Number of rows in the empty table. + #' @return TableHandle reference to the new table, which has not yet been named on the server. + #' See TableHandle$bind_to_variable() for naming a new table on the server. + empty_table = function(size) { + verify_int("size", size) + return(TableHandle$new(private$internal_client$empty_table(size))) + }, + + #' @description + #' Creates a ticking table. + #' @param start_time_nanos When the table should start ticking (in units of nanoseconds since the epoch). + #' @param period_nanos Table ticking frequency (in nanoseconds). + #' @return TableHandle reference to the new table, which has not yet been named on the server. + #' See TableHandle$bind_to_variable() for naming a new table on the server. + time_table = function(start_time_nanos, period_nanos) { + verify_int(start_time_nanos) + verify_int(period_nanos) + return(TableHandle$new(private$internal_client$time_table(start_time_nanos, period_nanos))) + } + #' @description #' Imports a new table to the Deephaven server. Note that this new table is not automatically bound to #' a variable name on the server. See `?TableHandle` for more information. diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index a68ce9cc801..6decfb97a99 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -68,6 +68,32 @@ agg_by <- function(th, aggregations) { return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations))) } +#' @export +first_by <- function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$first_by(columns))) +} + +#' @export +last_by <- function(th, columns) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$last_by(columns))) +} + +#' @export +head_by <- function(th, columns, n) { + verify_int("n", n) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$head_by(columns, n))) +} + +#' @export +tail_by <- function(th, columns, n) { + verify_int("n", n) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$tail_by(columns, n))) +} + #' @export min_by <- function(th, columns) { verify_string_vector("columns", columns) @@ -106,33 +132,21 @@ w_avg_by <- function(th, columns, weight_column) { } #' @export -var_by <- function(th, columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$var_by(columns))) -} - -#' @export -std_by <- function(th, columns) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$std_by(columns))) -} - -#' @export -first_by <- function(th, columns) { +median_by <- function(th, columns) { verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$first_by(columns))) + return(TableHandle$new(th$internal_table_handle$median_by(columns))) } #' @export -last_by <- function(th, columns) { +var_by <- function(th, columns) { verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$last_by(columns))) + return(TableHandle$new(th$internal_table_handle$var_by(columns))) } #' @export -median_by <- function(th, columns) { +std_by <- function(th, columns) { verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$median_by(columns))) + return(TableHandle$new(th$internal_table_handle$std_by(columns))) } #' @export @@ -150,17 +164,13 @@ count_by <- function(th, columns, count_by_column) { } #' @export -head_by <- function(th, columns, n) { - verify_int("n", n) - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$head_by(columns, n))) -} - -#' @export -tail_by <- function(th, columns, n) { - verify_int("n", n) +sort_by <- function(th, columns, descending = FALSE) { verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$tail_by(columns, n))) + verify_bool_vector("descending", descending) + if ((length(descending) > 1) && length(descending) != length(columns)) { + stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) + } + return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) } # JOIN OPERATIONS @@ -209,16 +219,6 @@ dh_ungroup.TableHandle <- function(th, null_fill, group_by_columns) { return(TableHandle$new(th$internal_table_handle$ungroup(null_fill, group_by_columns))) } -#' @export -sort_by <- function(th, columns, descending = FALSE) { - verify_string_vector("columns", columns) - verify_bool_vector("descending", descending) - if ((length(descending) > 1) && length(descending) != length(columns)) { - stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) - } - return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) -} - #' @export dh_merge.TableHandle <- function(th, key_column, sources) { verify_string("key_column", key_column) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 5063c854b15..1655626585b 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -19,12 +19,10 @@ class AggregateWrapper; class TableHandleWrapper; class ClientOptionsWrapper; class ClientWrapper; -class SortPairWrapper; // forward declaration of conversion functions std::vector convertRcppListToVectorOfTypeAggregate(Rcpp::List rcpp_list); std::vector convertRcppListToVectorOfTypeTableHandle(Rcpp::List rcpp_list); -std::vector convertRcppListToVectorOfTypeSortPair(Rcpp::List rcpp_list); // ######################### DH WRAPPERS ######################### @@ -62,6 +60,14 @@ AggregateWrapper* INTERNAL_max(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::max(columnSpecs)); } +AggregateWrapper* INTERNAL_first(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::first(columnSpecs)); +} + +AggregateWrapper* INTERNAL_last(std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::last(columnSpecs)); +} + AggregateWrapper* INTERNAL_sum(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::sum(columnSpecs)); } @@ -78,6 +84,10 @@ AggregateWrapper* INTERNAL_wAvg(std::string weightColumn, std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::med(columnSpecs)); +} + AggregateWrapper* INTERNAL_var(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::var(columnSpecs)); } @@ -86,18 +96,6 @@ AggregateWrapper* INTERNAL_std(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::std(columnSpecs)); } -AggregateWrapper* INTERNAL_first(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::first(columnSpecs)); -} - -AggregateWrapper* INTERNAL_last(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::last(columnSpecs)); -} - -AggregateWrapper* INTERNAL_median(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::med(columnSpecs)); -} - AggregateWrapper* INTERNAL_percentile(double percentile, std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::pct(percentile, false, columnSpecs)); } @@ -142,13 +140,29 @@ class TableHandleWrapper { // AGGREGATION OPERATIONS + TableHandleWrapper* by(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.by(columnSpecs)); + }; + TableHandleWrapper* aggBy(Rcpp::List aggregations) { std::vector converted_aggregations = convertRcppListToVectorOfTypeAggregate(aggregations); return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations))); } - TableHandleWrapper* by(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.by(columnSpecs)); + TableHandleWrapper* firstBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.firstBy(columnSpecs)); + }; + + TableHandleWrapper* lastBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.lastBy(columnSpecs)); + }; + + TableHandleWrapper* headBy(std::vector columnSpecs, int64_t n) { + return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); + }; + + TableHandleWrapper* tailBy(std::vector columnSpecs, int64_t n) { + return new TableHandleWrapper(internal_tbl_hdl.tailBy(n, columnSpecs)); }; TableHandleWrapper* minBy(std::vector columnSpecs) { @@ -175,6 +189,10 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.wAvgBy(weightColumn, columnSpecs)); }; + TableHandleWrapper* medianBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.medianBy(columnSpecs)); + }; + TableHandleWrapper* varBy(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.varBy(columnSpecs)); }; @@ -183,18 +201,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.stdBy(columnSpecs)); }; - TableHandleWrapper* firstBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.firstBy(columnSpecs)); - }; - - TableHandleWrapper* lastBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.lastBy(columnSpecs)); - }; - - TableHandleWrapper* medianBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.medianBy(columnSpecs)); - }; - TableHandleWrapper* percentileBy(std::vector columnSpecs, double percentile) { return new TableHandleWrapper(internal_tbl_hdl.percentileBy(percentile, columnSpecs)); }; @@ -203,14 +209,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.countBy(countByColumn, columnSpecs)); }; - TableHandleWrapper* headBy(std::vector columnSpecs, int64_t n) { - return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); - }; - - TableHandleWrapper* tailBy(std::vector columnSpecs, int64_t n) { - return new TableHandleWrapper(internal_tbl_hdl.tailBy(n, columnSpecs)); - }; - // JOIN OPERATIONS TableHandleWrapper* crossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { @@ -493,27 +491,20 @@ RCPP_MODULE(DeephavenInternalModule) { class_("INTERNAL_Aggregate") ; + function("INTERNAL_first", &INTERNAL_first); + function("INTERNAL_last", &INTERNAL_last); function("INTERNAL_min", &INTERNAL_min); function("INTERNAL_max", &INTERNAL_max); function("INTERNAL_sum", &INTERNAL_sum); function("INTERNAL_abs_sum", &INTERNAL_absSum); function("INTERNAL_avg", &INTERNAL_avg); function("INTERNAL_w_avg", &INTERNAL_wAvg); + function("INTERNAL_median", &INTERNAL_median); function("INTERNAL_var", &INTERNAL_var); function("INTERNAL_std", &INTERNAL_std); - function("INTERNAL_first", &INTERNAL_first); - function("INTERNAL_last", &INTERNAL_last); - function("INTERNAL_median", &INTERNAL_median); function("INTERNAL_percentile", &INTERNAL_percentile); function("INTERNAL_count", &INTERNAL_count); - - class_("INTERNAL_SortPair") - ; - function("INTERNAL_sort_asc", &INTERNAL_sortAsc); - function("INTERNAL_sort_desc", &INTERNAL_sortDesc); - - class_("INTERNAL_TableHandle") .method("select", &TableHandleWrapper::select) .method("view", &TableHandleWrapper::view) @@ -523,21 +514,21 @@ RCPP_MODULE(DeephavenInternalModule) { .method("where", &TableHandleWrapper::where) .method("agg_by", &TableHandleWrapper::aggBy) + .method("first_by", &TableHandleWrapper::firstBy) + .method("last_by", &TableHandleWrapper::lastBy) + .method("head_by", &TableHandleWrapper::headBy) + .method("tail_by", &TableHandleWrapper::tailBy) .method("min_by", &TableHandleWrapper::minBy) .method("max_by", &TableHandleWrapper::maxBy) .method("sum_by", &TableHandleWrapper::sumBy) .method("abs_sum_by", &TableHandleWrapper::absSumBy) .method("avg_by", &TableHandleWrapper::avgBy) .method("w_avg_by", &TableHandleWrapper::wAvgBy) + .method("median_by", &TableHandleWrapper::medianBy) .method("var_by", &TableHandleWrapper::varBy) .method("std_by", &TableHandleWrapper::stdBy) - .method("first_by", &TableHandleWrapper::firstBy) - .method("last_by", &TableHandleWrapper::lastBy) - .method("median_by", &TableHandleWrapper::medianBy) .method("percentile_by", &TableHandleWrapper::percentileBy) .method("count_by", &TableHandleWrapper::countBy) - .method("head_by", &TableHandleWrapper::headBy) - .method("tail_by", &TableHandleWrapper::tailBy) .method("cross_join", &TableHandleWrapper::crossJoin) .method("natural_join", &TableHandleWrapper::naturalJoin) From d33966c1dc0a811aefc20da57e793b0dd552f4aa Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 25 Jul 2023 16:41:32 -0500 Subject: [PATCH 20/73] Fix new table methods, add tests, add conversion functions to be used in queries --- R/rdeephaven/NAMESPACE | 6 +- R/rdeephaven/R/client_wrapper.R | 2 +- R/rdeephaven/R/table_handle_wrapper.R | 15 + .../tests/testthat/test_table_operations.R | 282 ++++++++++-------- R/rdeephaven/man/Client.Rd | 46 +++ 5 files changed, 223 insertions(+), 128 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index d9390a40d9f..3f23dad0703 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -14,7 +14,6 @@ S3method(where,TableHandle) export(Aggregation) export(Client) export(ClientOptions) -export(Sorter) export(TableHandle) export(abs_sum_by) export(agg_abs_sum) @@ -31,6 +30,9 @@ export(agg_std) export(agg_sum) export(agg_var) export(agg_w_avg) +export(as.arrow.record.batch.reader) +export(as.arrow.table) +export(as.tibble) export(avg_by) export(count_by) export(cross_join) @@ -46,9 +48,7 @@ export(median_by) export(min_by) export(natural_join) export(percentile_by) -export(sort_asc) export(sort_by) -export(sort_desc) export(std_by) export(sum_by) export(tail_by) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 68b274867f7..e42452b207c 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -72,7 +72,7 @@ Client <- R6Class("Client", cloneable = FALSE, verify_int(start_time_nanos) verify_int(period_nanos) return(TableHandle$new(private$internal_client$time_table(start_time_nanos, period_nanos))) - } + }, #' @description #' Imports a new table to the Deephaven server. Note that this new table is not automatically bound to diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index a0aed706bf5..6507bbecfdf 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -109,6 +109,21 @@ TableHandle <- R6Class("TableHandle", cloneable = FALSE, ### S3 METHODS +#' @export +as.arrow.record.batch.reader <- function(th) { + return(th$to_arrow_record_batch_reader()) +} + +#' @export +as.arrow.table <- function(th) { + return(th$to_arrow_table()) +} + +#' @export +as.tibble <- function(th) { + return(th$to_tibble()) +} + #' @export as.data.frame.TableHandle <- function(x, ...) { x$to_data_frame() diff --git a/R/rdeephaven/inst/tests/testthat/test_table_operations.R b/R/rdeephaven/inst/tests/testthat/test_table_operations.R index e16730e9aac..5b39921d3a2 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_operations.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_operations.R @@ -236,6 +236,88 @@ test_that("where behaves as expected", { expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) }) +test_that("first_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), first)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + first_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), first)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + first_by(c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) +}) + +test_that("last_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), last)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + last_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), last)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + last_by(c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) +}) + +test_that("head_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 %>% + group_by(X) %>% + slice_head(n=2) + new_th1 <- data$th5 %>% + head_by("X", 2) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + slice_head(n=2) + new_th2 <- data$th5 %>% + head_by(c("X", "Y"), 2) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) +}) + +test_that("tail_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 %>% + group_by(X) %>% + slice_tail(n=2) + new_th1 <- data$th5 %>% + tail_by("X", 2) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + slice_tail(n=2) + new_th2 <- data$th5 %>% + tail_by(c("X", "Y"), 2) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) +}) + test_that("min_by behaves as expected", { data <- setup() @@ -358,70 +440,26 @@ test_that("abs_sum_by behaves as expected", { expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -test_that("var_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - select(-Y) %>% - group_by(X) %>% - summarise(across(everything(), var)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - var_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - group_by(X, Y) %>% - summarise(across(everything(), var)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - var_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) -}) - -test_that("std_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - select(-Y) %>% - group_by(X) %>% - summarise(across(everything(), sd)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - std_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - group_by(X, Y) %>% - summarise(across(everything(), sd)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - std_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) -}) - test_that("avg_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - select(-Y) %>% - group_by(X) %>% - summarise(across(everything(), mean)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - avg_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - group_by(X, Y) %>% - summarise(across(everything(), mean)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - avg_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), mean)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + avg_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), mean)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + avg_by(c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) # TODO: I think that the current behavior of wAvgBy() is wrong and needs to be updated @@ -429,68 +467,68 @@ test_that("w_avg_by behaves as expected", { data <- setup() }) -test_that("first_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - select(-Y) %>% - group_by(X) %>% - summarise(across(everything(), first)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - first_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - group_by(X, Y) %>% - summarise(across(everything(), first)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - first_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) +test_that("median_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + group_by(X) %>% + summarise(across(everything(), median)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + median_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + group_by(X, Y) %>% + summarise(across(everything(), median)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + median_by(c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -test_that("last_by behaves as expected", { +test_that("var_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% select(-Y) %>% group_by(X) %>% - summarise(across(everything(), last)) + summarise(across(everything(), var)) new_th1 <- data$th5 %>% drop_columns("Y") %>% - last_by("X") + var_by("X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% group_by(X, Y) %>% - summarise(across(everything(), last)) %>% + summarise(across(everything(), var)) %>% arrange(X, Y) new_th2 <- data$th5 %>% - last_by(c("X", "Y")) %>% + var_by(c("X", "Y")) %>% sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -test_that("median_by behaves as expected", { +test_that("std_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% select(-Y) %>% group_by(X) %>% - summarise(across(everything(), median)) + summarise(across(everything(), sd)) new_th1 <- data$th5 %>% drop_columns("Y") %>% - median_by("X") + std_by("X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% group_by(X, Y) %>% - summarise(across(everything(), median)) %>% + summarise(across(everything(), sd)) %>% arrange(X, Y) new_th2 <- data$th5 %>% - median_by(c("X", "Y")) %>% + std_by(c("X", "Y")) %>% sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -536,42 +574,38 @@ test_that("count_by behaves as expected", { expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -test_that("head_by behaves as expected", { +test_that("sort_by behaves as expected", { data <- setup() - new_tb1 <- data$df5 %>% - group_by(X) %>% - slice_head(n=2) - new_th1 <- data$th5 %>% - head_by("X", 2) + new_tb1 <- data$df1 %>% + arrange(dbl_col) + new_th1 <- data$th1 %>% + sort_by("dbl_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - new_tb2 <- data$df5 %>% - group_by(X, Y) %>% - slice_head(n=2) - new_th2 <- data$th5 %>% - head_by(c("X", "Y"), 2) %>% - sort_by(c("X", "Y")) + new_tb2 <- data$df2 %>% + arrange(desc(col3)) + new_th2 <- data$th2 %>% + sort_by("col3", descending = TRUE) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) -}) - -test_that("tail_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - group_by(X) %>% - slice_tail(n=2) - new_th1 <- data$th5 %>% - tail_by("X", 2) - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - group_by(X, Y) %>% - slice_tail(n=2) - new_th2 <- data$th5 %>% - tail_by(c("X", "Y"), 2) %>% - sort_by(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + arrange(X1, X2, X3, X4, X5) + new_th3 <- data$th3 %>% + sort_by(c("X1", "X2", "X3", "X4", "X5")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + arrange(desc(bool_col), desc(int_col)) + new_th4 <- data$th4 %>% + sort_by(c("bool_col", "int_col"), descending = TRUE) + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + arrange(X, desc(Y), Number1) + new_th5 <- data$th5 %>% + sort_by(c("X", "Y", "Number1"), descending = c(FALSE, TRUE, FALSE)) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) }) # TODO: Our definition of a cross join is significantly different from dplyr diff --git a/R/rdeephaven/man/Client.Rd b/R/rdeephaven/man/Client.Rd index 296453084ae..d39feec15c7 100644 --- a/R/rdeephaven/man/Client.Rd +++ b/R/rdeephaven/man/Client.Rd @@ -29,6 +29,8 @@ client$run_script("print([i for i in range(10)])") \itemize{ \item \href{#method-Client-new}{\code{Client$new()}} \item \href{#method-Client-open_table}{\code{Client$open_table()}} +\item \href{#method-Client-empty_table}{\code{Client$empty_table()}} +\item \href{#method-Client-time_table}{\code{Client$time_table()}} \item \href{#method-Client-import_table}{\code{Client$import_table()}} \item \href{#method-Client-run_script}{\code{Client$run_script()}} } @@ -74,6 +76,50 @@ TableHandle reference to the requested table. } } \if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Client-empty_table}{}}} +\subsection{Method \code{empty_table()}}{ +Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Client$empty_table(size)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{size}}{Number of rows in the empty table.} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +TableHandle reference to the new table, which has not yet been named on the server. + See TableHandle$bind_to_variable() for naming a new table on the server. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Client-time_table}{}}} +\subsection{Method \code{time_table()}}{ +Creates a ticking table. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Client$time_table(start_time_nanos, period_nanos)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{start_time_nanos}}{When the table should start ticking (in units of nanoseconds since the epoch).} + +\item{\code{period_nanos}}{Table ticking frequency (in nanoseconds).} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +TableHandle reference to the new table, which has not yet been named on the server. + See TableHandle$bind_to_variable() for naming a new table on the server. +} +} +\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Client-import_table}{}}} \subsection{Method \code{import_table()}}{ From e7bf936a79250c5d40b6c387168de47c4e6f1ee1 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 25 Jul 2023 17:11:45 -0500 Subject: [PATCH 21/73] Update generics --- R/rdeephaven/NAMESPACE | 5 ++--- R/rdeephaven/R/table_handle_wrapper.R | 17 ++++++----------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 3f23dad0703..2059c879eb4 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -1,6 +1,8 @@ # Generated by roxygen2: do not edit by hand S3method(as.data.frame,TableHandle) +S3method(as_arrow_table,TableHandle) +S3method(as_tibble,TableHandle) S3method(dh_merge,TableHandle) S3method(dh_ungroup,TableHandle) S3method(drop_columns,TableHandle) @@ -30,9 +32,6 @@ export(agg_std) export(agg_sum) export(agg_var) export(agg_w_avg) -export(as.arrow.record.batch.reader) -export(as.arrow.table) -export(as.tibble) export(avg_by) export(count_by) export(cross_join) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 6507bbecfdf..7eceb0ad535 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -110,21 +110,16 @@ TableHandle <- R6Class("TableHandle", cloneable = FALSE, ### S3 METHODS #' @export -as.arrow.record.batch.reader <- function(th) { - return(th$to_arrow_record_batch_reader()) +as_arrow_table.TableHandle <- function(th, ...) { + th$to_arrow_table() } #' @export -as.arrow.table <- function(th) { - return(th$to_arrow_table()) +as_tibble.TableHandle <- function(th, ...) { + th$to_tibble() } #' @export -as.tibble <- function(th) { - return(th$to_tibble()) -} - -#' @export -as.data.frame.TableHandle <- function(x, ...) { - x$to_data_frame() +as.data.frame.TableHandle <- function(th, ...) { + th$to_data_frame() } From a3c8d6ef6627f03850c3ff6c51cb26957613296d Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 26 Jul 2023 09:09:27 -0500 Subject: [PATCH 22/73] Reorder agg_by ops, start agg_by testing --- R/rdeephaven/R/aggregate_wrapper.R | 36 ++++---- .../inst/tests/testthat/test_agg_by.R | 88 +++++++++++++++++++ ...st_table_operations.R => test_table_ops.R} | 0 3 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 R/rdeephaven/inst/tests/testthat/test_agg_by.R rename R/rdeephaven/inst/tests/testthat/{test_table_operations.R => test_table_ops.R} (100%) diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R index b7377c30ff2..6396a0f1d1b 100644 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -17,6 +17,18 @@ Aggregation <- R6Class("Aggregation", cloneable = FALSE, ### All of the functions below return an instance of the above class +#' @export +agg_first = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_first(columns))) +} + +#' @export +agg_last = function(columns) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_last(columns))) +} + #' @export agg_min = function(columns) { verify_string_vector("columns", columns) @@ -55,33 +67,21 @@ agg_w_avg = function(weight_column, columns) { } #' @export -agg_var = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_var(columns))) -} - -#' @export -agg_std = function(columns) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_std(columns))) -} - -#' @export -agg_first = function(columns) { +agg_median = function(columns) { verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_first(columns))) + return(Aggregation$new(INTERNAL_median(columns))) } #' @export -agg_last = function(columns) { +agg_var = function(columns) { verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_last(columns))) + return(Aggregation$new(INTERNAL_var(columns))) } #' @export -agg_median = function(columns) { +agg_std = function(columns) { verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_median(columns))) + return(Aggregation$new(INTERNAL_std(columns))) } #' @export diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R new file mode 100644 index 00000000000..b4e49e78af7 --- /dev/null +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -0,0 +1,88 @@ +library(testthat) +library(rdeephaven) + +setup <- function() { + + df1 <- data.frame(string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00)) + + df2 <- data.frame(col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100)) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE)) + + df5 <- data.frame(X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), + Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), + Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214)) + + df6 <- data.frame(X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), + Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), + Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), + Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6)) + + # in order to test TableHandle, we need to have tables on the server that we know everything about. + # thus, we have to push these created tables to the server and get TableHandles to each of them. + # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() + + # set up client + client_options <- ClientOptions$new() + client <- Client$new(target="localhost:10000", client_options=client_options) + + # move dataframes to server and get TableHandles for testing + th1 <- client$import_table(df1) + th2 <- client$import_table(df2) + th3 <- client$import_table(df3) + th4 <- client$import_table(df4) + th5 <- client$import_table(df5) + th6 <- client$import_table(df6) + + return(list("client" = client, + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6)) +} + +test_that("agg_first behaves as expected", { +}) + +test_that("agg_last behaves as expected", { +}) + +test_that("agg_min behaves as expected", { +}) + +test_that("agg_max behaves as expected", { +}) + +test_that("agg_sum behaves as expected", { +}) + +test_that("agg_abs_sum behaves as expected", { +}) + +test_that("agg_avg behaves as expected", { +}) + +test_that("agg_w_avg behaves as expected", { +}) + +test_that("agg_median behaves as expected", { +}) + +test_that("agg_var behaves as expected", { +}) + +test_that("agg_std behaves as expected", { +}) + +test_that("agg_percentile behaves as expected", { +}) + +test_that("agg_count behaves as expected", { +}) \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_table_operations.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R similarity index 100% rename from R/rdeephaven/inst/tests/testthat/test_table_operations.R rename to R/rdeephaven/inst/tests/testthat/test_table_ops.R From 1a7737028583a3c51d196ccee899027f3c9ddfd0 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 26 Jul 2023 15:30:27 -0500 Subject: [PATCH 23/73] enable empty _by and agg ops --- R/rdeephaven/NAMESPACE | 3 +- R/rdeephaven/R/aggregate_wrapper.R | 24 +++--- R/rdeephaven/R/helper_functions.R | 4 - R/rdeephaven/R/table_ops.R | 77 ++++++++--------- .../inst/tests/testthat/test_table_ops.R | 82 ++++++++++--------- R/rdeephaven/src/client.cpp | 28 ++++--- 6 files changed, 114 insertions(+), 104 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 2059c879eb4..fffe4c58820 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -4,7 +4,6 @@ S3method(as.data.frame,TableHandle) S3method(as_arrow_table,TableHandle) S3method(as_tibble,TableHandle) S3method(dh_merge,TableHandle) -S3method(dh_ungroup,TableHandle) S3method(drop_columns,TableHandle) S3method(head,TableHandle) S3method(select,TableHandle) @@ -40,6 +39,7 @@ export(dh_ungroup) export(drop_columns) export(exact_join) export(first_by) +export(group_by) export(head_by) export(last_by) export(max_by) @@ -51,6 +51,7 @@ export(sort_by) export(std_by) export(sum_by) export(tail_by) +export(ungroup) export(update_view) export(var_by) export(view) diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R index 6396a0f1d1b..fb12d337f11 100644 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -18,74 +18,74 @@ Aggregation <- R6Class("Aggregation", cloneable = FALSE, ### All of the functions below return an instance of the above class #' @export -agg_first = function(columns) { +agg_first = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_first(columns))) } #' @export -agg_last = function(columns) { +agg_last = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_last(columns))) } #' @export -agg_min = function(columns) { +agg_min = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_min(columns))) } #' @export -agg_max = function(columns) { +agg_max = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_max(columns))) } #' @export -agg_sum = function(columns) { +agg_sum = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_sum(columns))) } #' @export -agg_abs_sum = function(columns) { +agg_abs_sum = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_abs_sum(columns))) } #' @export -agg_avg = function(columns) { +agg_avg = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_avg(columns))) } #' @export -agg_w_avg = function(weight_column, columns) { +agg_w_avg = function(weight_column, columns = character()) { verify_string("weight_column", weight_column) verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) } #' @export -agg_median = function(columns) { +agg_median = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_median(columns))) } #' @export -agg_var = function(columns) { +agg_var = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_var(columns))) } #' @export -agg_std = function(columns) { +agg_std = function(columns = character()) { verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_std(columns))) } #' @export -agg_percentile = function(percentile, columns) { +agg_percentile = function(percentile, columns = character()) { verify_proportion("percentile", percentile) verify_string_vector("columns", columns) return(Aggregation$new(INTERNAL_percentile(percentile, columns))) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index c2d7bf04e62..9205fa6d4b4 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -67,7 +67,3 @@ verify_string_vector <- function(arg_name, string_vector_candidate) { strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { return(r6_aggregation$internal_aggregation) } - -strip_r6_wrapping_from_sorter <- function(r6_sorter) { - return(r6_sorter$internal_sorter) -} \ No newline at end of file diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 6decfb97a99..5d6df2ed29d 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -20,31 +20,31 @@ dh_merge <- function(x, ...) {UseMethod("dh_merge", x)} ### S3 METHODS (implemented generics) #' @export -select.TableHandle <- function(th, columns) { +select.TableHandle <- function(th, columns = character()) { verify_string_vector("columns", columns) TableHandle$new(th$internal_table_handle$select(columns)) } #' @export -view.TableHandle <- function(th, columns) { +view.TableHandle <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$view(columns))) } #' @export -update.TableHandle <- function(th, columns) { +update.TableHandle <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$update(columns))) } #' @export -update_view.TableHandle <- function(th, columns) { +update_view.TableHandle <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$update_view(columns))) } #' @export -drop_columns.TableHandle <- function(th, columns) { +drop_columns.TableHandle <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$drop_columns(columns))) } @@ -57,110 +57,119 @@ where.TableHandle <- function(th, condition) { # AGGREGATION OPERATIONS +#' @export +group_by <- function(th, group_by_columns = character()) { + verify_string_vector("group_by_columns", group_by_columns) + return(TableHandle$new(th$internal_table_handle$group_by(group_by_columns))) +} + +#' @export +ungroup <- function(th, group_by_columns = character()) { + verify_string_vector("group_by_columns", group_by_columns) + return(TableHandle$new(th$internal_table_handle$ungroup(group_by_columns))) +} + #' @export agg_by <- function(th, aggregations) { verify_internal_type("Aggregation", "aggregations", aggregations) - if (length(aggregations) == 1) { - aggregations = c(aggregations) - } + aggregations = c(aggregations) unwrapped_aggregations = lapply(aggregations, strip_r6_wrapping_from_aggregation) - return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations))) } #' @export -first_by <- function(th, columns) { - verify_string_vector("columns", columns) +first_by <- function(th, columns = character()) { + #verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$first_by(columns))) } #' @export -last_by <- function(th, columns) { +last_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$last_by(columns))) } #' @export -head_by <- function(th, columns, n) { +head_by <- function(th, n, columns = character()) { verify_int("n", n) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$head_by(columns, n))) + return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) } #' @export -tail_by <- function(th, columns, n) { +tail_by <- function(th, n, columns = character()) { verify_int("n", n) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$tail_by(columns, n))) + return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) } #' @export -min_by <- function(th, columns) { +min_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$min_by(columns))) } #' @export -max_by <- function(th, columns) { +max_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$max_by(columns))) } #' @export -sum_by <- function(th, columns) { +sum_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$sum_by(columns))) } #' @export -abs_sum_by <- function(th, columns) { +abs_sum_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) } #' @export -avg_by <- function(th, columns) { +avg_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$avg_by(columns))) } #' @export -w_avg_by <- function(th, columns, weight_column) { +w_avg_by <- function(th, weight_column, columns = character()) { verify_string("weight_column", weight_column) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$w_avg_by(columns, weight_column))) + return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) } #' @export -median_by <- function(th, columns) { +median_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$median_by(columns))) } #' @export -var_by <- function(th, columns) { +var_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$var_by(columns))) } #' @export -std_by <- function(th, columns) { +std_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$std_by(columns))) } #' @export -percentile_by <- function(th, columns, percentile) { - verify_string_vector("columns", columns) +percentile_by <- function(th, percentile, columns = character()) { verify_proportion("percentile", percentile) - return(TableHandle$new(th$internal_table_handle$percentile_by(columns, percentile))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$percentile_by(percentile, columns))) } #' @export -count_by <- function(th, columns, count_by_column) { +count_by <- function(th, count_by_column, columns = character()) { verify_string("count_by_column", count_by_column) verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$count_by(columns, count_by_column))) + return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) } #' @export @@ -213,12 +222,6 @@ tail.TableHandle <- function(th, n) { return(TableHandle$new(th$internal_table_handle$tail(n))) } -#' @export -dh_ungroup.TableHandle <- function(th, null_fill, group_by_columns) { - verify_string_vector("group_by_columns", group_by_columns) - return(TableHandle$new(th$internal_table_handle$ungroup(null_fill, group_by_columns))) -} - #' @export dh_merge.TableHandle <- function(th, key_column, sources) { verify_string("key_column", key_column) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 5b39921d3a2..b99adebbd45 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -236,12 +236,20 @@ test_that("where behaves as expected", { expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) }) +test_that("group_by behaves as expected", { + data <- setup() +}) + +test_that("ungroup behaves as expected", { + data <- setup() +}) + test_that("first_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% select(-Y) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), first)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -249,7 +257,7 @@ test_that("first_by behaves as expected", { expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), first)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -263,7 +271,7 @@ test_that("last_by behaves as expected", { new_tb1 <- data$df5 %>% select(-Y) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), last)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -271,7 +279,7 @@ test_that("last_by behaves as expected", { expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), last)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -284,17 +292,17 @@ test_that("head_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - group_by(X) %>% + dplyr::group_by(X) %>% slice_head(n=2) new_th1 <- data$th5 %>% - head_by("X", 2) + head_by(2, "X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% slice_head(n=2) new_th2 <- data$th5 %>% - head_by(c("X", "Y"), 2) %>% + head_by(2, c("X", "Y")) %>% sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -303,17 +311,17 @@ test_that("tail_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - group_by(X) %>% + dplyr::group_by(X) %>% slice_tail(n=2) new_th1 <- data$th5 %>% - tail_by("X", 2) + tail_by(2, "X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% slice_tail(n=2) new_th2 <- data$th5 %>% - tail_by(c("X", "Y"), 2) %>% + tail_by(2, c("X", "Y")) %>% sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -322,14 +330,14 @@ test_that("min_by behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - group_by(int_col) %>% + dplyr::group_by(int_col) %>% summarise(across(everything(), min)) new_th1 <- data$th1 %>% min_by("int_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - group_by(col2) %>% + dplyr::group_by(col2) %>% summarise(across(everything(), min)) new_th2 <- data$th2 %>% min_by("col2") @@ -337,7 +345,7 @@ test_that("min_by behaves as expected", { new_tb3 <- data$df3 %>% mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% - group_by(bool_col1, bool_col2) %>% + dplyr::group_by(bool_col1, bool_col2) %>% summarise(across(everything(), min)) %>% arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same new_th3 <- data$th3 %>% @@ -347,7 +355,7 @@ test_that("min_by behaves as expected", { expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% - group_by(bool_col) %>% + dplyr::group_by(bool_col) %>% summarise(across(everything(), min)) %>% arrange(bool_col) new_th4 <- data$th4 %>% @@ -360,14 +368,14 @@ test_that("max_by behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - group_by(int_col) %>% + dplyr::group_by(int_col) %>% summarise(across(everything(), max)) new_th1 <- data$th1 %>% max_by("int_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - group_by(col2) %>% + dplyr::group_by(col2) %>% summarise(across(everything(), max)) new_th2 <- data$th2 %>% max_by("col2") @@ -375,17 +383,17 @@ test_that("max_by behaves as expected", { new_tb3 <- data$df3 %>% mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% - group_by(bool_col1, bool_col2) %>% + dplyr::group_by(bool_col1, bool_col2) %>% summarise(across(everything(), max)) %>% arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same new_th3 <- data$th3 %>% update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% max_by(c("bool_col1", "bool_col2")) %>% - max_by(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same + sort_by(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% - group_by(bool_col) %>% + dplyr::group_by(bool_col) %>% summarise(across(everything(), max)) %>% arrange(bool_col) new_th4 <- data$th4 %>% @@ -399,7 +407,7 @@ test_that("sum_by behaves as expected", { new_tb1 <- data$df5 %>% select(-Y) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), sum)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -407,7 +415,7 @@ test_that("sum_by behaves as expected", { expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), sum)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -422,7 +430,7 @@ test_that("abs_sum_by behaves as expected", { new_tb1 <- data$df5 %>% select(-Y) %>% mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), sum)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -431,7 +439,7 @@ test_that("abs_sum_by behaves as expected", { new_tb2 <- data$df5 %>% mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), sum)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -445,7 +453,7 @@ test_that("avg_by behaves as expected", { new_tb1 <- data$df5 %>% select(-Y) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), mean)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -453,7 +461,7 @@ test_that("avg_by behaves as expected", { expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), mean)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -472,7 +480,7 @@ test_that("median_by behaves as expected", { new_tb1 <- data$df5 %>% select(-Y) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), median)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -480,7 +488,7 @@ test_that("median_by behaves as expected", { expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), median)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -494,7 +502,7 @@ test_that("var_by behaves as expected", { new_tb1 <- data$df5 %>% select(-Y) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), var)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -502,7 +510,7 @@ test_that("var_by behaves as expected", { expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), var)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -516,7 +524,7 @@ test_that("std_by behaves as expected", { new_tb1 <- data$df5 %>% select(-Y) %>% - group_by(X) %>% + dplyr::group_by(X) %>% summarise(across(everything(), sd)) new_th1 <- data$th5 %>% drop_columns("Y") %>% @@ -524,7 +532,7 @@ test_that("std_by behaves as expected", { expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% - group_by(X, Y) %>% + dplyr::group_by(X, Y) %>% summarise(across(everything(), sd)) %>% arrange(X, Y) new_th2 <- data$th5 %>% @@ -544,7 +552,7 @@ test_that("percentile_by behaves as expected", { Number2 = c(-50, 76, 130)) new_th1 <- data$th5 %>% drop_columns("Y") %>% - percentile_by("X", 0.4) + percentile_by(0.4, "X") expect_equal(as.data.frame(new_th1), new_df1) new_df2 <- data.frame(X = c("A", "B", "A", "C", "B", "B", "C"), @@ -552,7 +560,7 @@ test_that("percentile_by behaves as expected", { Number1 = c(50, -44, 49, 11, -66, 29, -70), Number2 = c(-55, 76, 20, 130, 137, 73, 214)) new_th2 <- data$th5 %>% - percentile_by(c("X", "Y"), 0.4) + percentile_by(0.4, c("X", "Y")) expect_equal(as.data.frame(new_th2), new_df2) }) @@ -563,13 +571,13 @@ test_that("count_by behaves as expected", { new_tb1 <- data$df5 %>% count(X) new_th1 <- data$th5 %>% - count_by("X", "n") + count_by("n", "X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df5 %>% count(X, Y) new_th2 <- data$th5 %>% - count_by(c("X", "Y"), "n") %>% + count_by("n", c("X", "Y")) %>% sort_by(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 1655626585b..57b5b22dfb6 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -138,12 +138,16 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.where(condition)); }; - // AGGREGATION OPERATIONS - - TableHandleWrapper* by(std::vector columnSpecs) { + TableHandleWrapper* groupBy(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.by(columnSpecs)); }; + TableHandleWrapper* ungroup(std::vector groupByColumns) { + return new TableHandleWrapper(internal_tbl_hdl.ungroup(false, groupByColumns)); + }; + + // AGGREGATION OPERATIONS + TableHandleWrapper* aggBy(Rcpp::List aggregations) { std::vector converted_aggregations = convertRcppListToVectorOfTypeAggregate(aggregations); return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations))); @@ -157,11 +161,11 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.lastBy(columnSpecs)); }; - TableHandleWrapper* headBy(std::vector columnSpecs, int64_t n) { + TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); }; - TableHandleWrapper* tailBy(std::vector columnSpecs, int64_t n) { + TableHandleWrapper* tailBy(int64_t n, std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.tailBy(n, columnSpecs)); }; @@ -185,7 +189,7 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.avgBy(columnSpecs)); }; - TableHandleWrapper* wAvgBy(std::vector columnSpecs, std::string weightColumn) { + TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.wAvgBy(weightColumn, columnSpecs)); }; @@ -201,11 +205,11 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.stdBy(columnSpecs)); }; - TableHandleWrapper* percentileBy(std::vector columnSpecs, double percentile) { + TableHandleWrapper* percentileBy(double percentile, std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.percentileBy(percentile, columnSpecs)); }; - TableHandleWrapper* countBy(std::vector columnSpecs, std::string countByColumn) { + TableHandleWrapper* countBy(std::string countByColumn, std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.countBy(countByColumn, columnSpecs)); }; @@ -233,10 +237,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.tail(n)); }; - TableHandleWrapper* ungroup(bool nullFill, std::vector groupByColumns) { - return new TableHandleWrapper(internal_tbl_hdl.ungroup(nullFill, groupByColumns)); - }; - TableHandleWrapper* merge(std::string keyColumn, Rcpp::List sources) { std::vector converted_sources = convertRcppListToVectorOfTypeTableHandle(sources); return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, converted_sources)); @@ -513,6 +513,9 @@ RCPP_MODULE(DeephavenInternalModule) { .method("drop_columns", &TableHandleWrapper::dropColumns) .method("where", &TableHandleWrapper::where) + .method("group_by", &TableHandleWrapper::groupBy) + .method("ungroup", &TableHandleWrapper::ungroup) + .method("agg_by", &TableHandleWrapper::aggBy) .method("first_by", &TableHandleWrapper::firstBy) .method("last_by", &TableHandleWrapper::lastBy) @@ -536,7 +539,6 @@ RCPP_MODULE(DeephavenInternalModule) { .method("head", &TableHandleWrapper::head) .method("tail", &TableHandleWrapper::tail) - .method("ungroup", &TableHandleWrapper::ungroup) .method("merge", &TableHandleWrapper::merge) .method("sort", &TableHandleWrapper::sort) From db784182d119b3d2a8e52ada11e34554b42fa21d Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 26 Jul 2023 18:45:34 -0500 Subject: [PATCH 24/73] agg_by testing --- R/rdeephaven/NAMESPACE | 1 + R/rdeephaven/R/table_handle_wrapper.R | 6 + R/rdeephaven/R/table_ops.R | 7 +- .../inst/tests/testthat/test_agg_by.R | 490 ++++++++++++++++++ .../inst/tests/testthat/test_table_ops.R | 3 + R/rdeephaven/src/client.cpp | 4 +- 6 files changed, 506 insertions(+), 5 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index fffe4c58820..5f15e010dc0 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -6,6 +6,7 @@ S3method(as_tibble,TableHandle) S3method(dh_merge,TableHandle) S3method(drop_columns,TableHandle) S3method(head,TableHandle) +S3method(print,TableHandle) S3method(select,TableHandle) S3method(tail,TableHandle) S3method(update,TableHandle) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 7eceb0ad535..c82af5fffa8 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -109,6 +109,12 @@ TableHandle <- R6Class("TableHandle", cloneable = FALSE, ### S3 METHODS +#' @export +print.TableHandle <- function(th, ...) { + cat("A Deephaven TableHandle:\n") + print(th$to_data_frame()) +} + #' @export as_arrow_table.TableHandle <- function(th, ...) { th$to_arrow_table() diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 5d6df2ed29d..095f8c41d63 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -70,16 +70,17 @@ ungroup <- function(th, group_by_columns = character()) { } #' @export -agg_by <- function(th, aggregations) { +agg_by <- function(th, aggregations, group_by_columns = character()) { verify_internal_type("Aggregation", "aggregations", aggregations) + verify_string_vector("group_by_columns", group_by_columns) aggregations = c(aggregations) unwrapped_aggregations = lapply(aggregations, strip_r6_wrapping_from_aggregation) - return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations))) + return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, group_by_columns))) } #' @export first_by <- function(th, columns = character()) { - #verify_string_vector("columns", columns) + verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$first_by(columns))) } diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index b4e49e78af7..9fb1d2c0d32 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -49,36 +49,526 @@ setup <- function() { } test_that("agg_first behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = first(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_first("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = first(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_first("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = first(X5), X6 = first(X6), X7 = first(X7), X8 = first(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_first(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(time_col = first(time_col), int_col = first(int_col)) + new_th4 <- data$th4 %>% + agg_by(c(agg_first("time_col"), agg_first("int_col")), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = first(Number1), Number2 = first(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_first(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = first(Number1), Number2 = first(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_first(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_last behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = last(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_last("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = last(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_last("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = last(X5), X6 = last(X6), X7 = last(X7), X8 = last(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_last(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(time_col = last(time_col), int_col = last(int_col)) + new_th4 <- data$th4 %>% + agg_by(c(agg_last("time_col"), agg_last("int_col")), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = last(Number1), Number2 = last(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_last(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = last(Number1), Number2 = last(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_last(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_min behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = min(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_min("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = min(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_min("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = min(X5), X6 = min(X6), X7 = min(X7), X8 = min(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_min(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(time_col = min(time_col), int_col = min(int_col)) + new_th4 <- data$th4 %>% + agg_by(c(agg_min("time_col"), agg_min("int_col")), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = min(Number1), Number2 = min(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_min(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = min(Number1), Number2 = min(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_min(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_max behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = max(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_max("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = max(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_max("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = max(X5), X6 = max(X6), X7 = max(X7), X8 = max(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_max(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(time_col = max(time_col), int_col = max(int_col)) + new_th4 <- data$th4 %>% + agg_by(c(agg_max("time_col"), agg_max("int_col")), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = max(Number1), Number2 = max(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_max(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = max(Number1), Number2 = max(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_max(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_sum behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = sum(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_sum("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = sum(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_sum("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = sum(X5), X6 = sum(X6), X7 = sum(X7), X8 = sum(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(int_col = sum(int_col)) + new_th4 <- data$th4 %>% + agg_by(agg_sum("int_col"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = sum(Number1), Number2 = sum(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_sum(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = sum(Number1), Number2 = sum(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_sum(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_abs_sum behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = sum(abs(int_col))) + new_th1 <- data$th1 %>% + agg_by(agg_abs_sum("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = sum(abs(col3))) + new_th2 <- data$th2 %>% + agg_by(agg_abs_sum("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = sum(abs(X5)), X6 = sum(abs(X6)), X7 = sum(abs(X7)), X8 = sum(abs(X8))) + new_th3 <- data$th3 %>% + agg_by(agg_abs_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(int_col = sum(abs(int_col))) + new_th4 <- data$th4 %>% + agg_by(agg_abs_sum("int_col"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) + new_th5 <- data$th5 %>% + agg_by(agg_abs_sum(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) + new_th6 <- data$th6 %>% + agg_by(agg_abs_sum(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_avg behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = mean(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_avg("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = mean(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_avg("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = mean(X5), X6 = mean(X6), X7 = mean(X7), X8 = mean(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_avg(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(int_col = mean(int_col)) + new_th4 <- data$th4 %>% + agg_by(agg_avg("int_col"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = mean(Number1), Number2 = mean(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_avg(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = mean(Number1), Number2 = mean(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_avg(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_w_avg behaves as expected", { }) test_that("agg_median behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = median(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_median("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = median(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_median("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = median(X5), X6 = median(X6), X7 = median(X7), X8 = median(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_median(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(int_col = median(int_col)) + new_th4 <- data$th4 %>% + agg_by(agg_median("int_col"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = median(Number1), Number2 = median(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_median(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = median(Number1), Number2 = median(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_median(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_var behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = var(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_var("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = var(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_var("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = var(X5), X6 = var(X6), X7 = var(X7), X8 = var(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_var(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(int_col = var(int_col)) + new_th4 <- data$th4 %>% + agg_by(agg_var("int_col"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = var(Number1), Number2 = var(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_var(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = var(Number1), Number2 = var(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_var(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_std behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = sd(int_col)) + new_th1 <- data$th1 %>% + agg_by(agg_std("int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = sd(col3)) + new_th2 <- data$th2 %>% + agg_by(agg_std("col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = sd(X5), X6 = sd(X6), X7 = sd(X7), X8 = sd(X8)) + new_th3 <- data$th3 %>% + agg_by(agg_std(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(int_col = sd(int_col)) + new_th4 <- data$th4 %>% + agg_by(agg_std("int_col"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + summarise(Number1 = sd(Number1), Number2 = sd(Number2)) + new_th5 <- data$th5 %>% + agg_by(agg_std(c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = sd(Number1), Number2 = sd(Number2)) + new_th6 <- data$th6 %>% + agg_by(agg_std(c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_percentile behaves as expected", { diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index b99adebbd45..3cb5ee7c510 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -50,6 +50,8 @@ setup <- function() { ##### TESTING GOOD INPUTS ##### +# TODO: Test all of the following with default inputs + test_that("select behaves as expected", { data <- setup() @@ -236,6 +238,7 @@ test_that("where behaves as expected", { expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) }) +# TODO: Test group_by and ungroup test_that("group_by behaves as expected", { data <- setup() }) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 57b5b22dfb6..0be1a4655cb 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -148,9 +148,9 @@ class TableHandleWrapper { // AGGREGATION OPERATIONS - TableHandleWrapper* aggBy(Rcpp::List aggregations) { + TableHandleWrapper* aggBy(Rcpp::List aggregations, std::vector groupByColumns) { std::vector converted_aggregations = convertRcppListToVectorOfTypeAggregate(aggregations); - return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations))); + return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations), groupByColumns)); } TableHandleWrapper* firstBy(std::vector columnSpecs) { From da79c54f3e99fbb36e8f066a6519e730827f9d99 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 27 Jul 2023 10:28:26 -0500 Subject: [PATCH 25/73] Finish agg_by testing --- .../inst/tests/testthat/test_agg_by.R | 125 ++++++++++++++++++ .../inst/tests/testthat/test_table_ops.R | 25 +++- 2 files changed, 149 insertions(+), 1 deletion(-) diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index 9fb1d2c0d32..4b07f3fedd2 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -413,6 +413,61 @@ test_that("agg_avg behaves as expected", { }) test_that("agg_w_avg behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(string_col) %>% + summarise(int_col = weighted.mean(int_col, dbl_col)) + new_th1 <- data$th1 %>% + agg_by(agg_w_avg("dbl_col", "int_col"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col1, col2) %>% + summarise(col3 = weighted.mean(col3, col1)) + new_th2 <- data$th2 %>% + agg_by(agg_w_avg("col1", "col3"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::group_by(X1, X2, X3, X4) %>% + summarise(X5 = weighted.mean(X5, X9), X6 = weighted.mean(X6, X9), + X7 = weighted.mean(X7, X9), X8 = weighted.mean(X8, X9)) + new_th3 <- data$th3 %>% + agg_by(agg_w_avg("X9", c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(int_col = weighted.mean(int_col, int_col)) + new_th4 <- data$th4 %>% + agg_by(agg_w_avg("int_col", "int_col"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + dplyr::group_by(X) %>% + mutate(weights = Number1 * Number2) %>% + summarise(Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights)) + new_th5 <- data$th5 %>% + update("weights = Number1 * Number2") %>% + agg_by(agg_w_avg("weights", c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + dplyr::group_by(X, Y) %>% + mutate(weights = Number1 * Number2) %>% + summarise(Number1 = weighted.mean(Number1, weights), Number2 = weighted.mean(Number2, weights)) + new_th6 <- data$th6 %>% + update("weights = Number1 * Number2") %>% + agg_by(agg_w_avg("weights", c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) test_that("agg_median behaves as expected", { @@ -572,7 +627,77 @@ test_that("agg_std behaves as expected", { }) test_that("agg_percentile behaves as expected", { + + # There is not a clean analog to agg_percentile in dplyr, so we create the + # dataframes directly, and only make comparisons on deterministic data frames. + + data <- setup() + + new_df1 <- data.frame(int_col = 2) + new_th1 <- data$th1 %>% + agg_by(agg_percentile(0.4, "int_col")) + expect_equal(as.data.frame(new_th1), new_df1) + + new_df2 <- data.frame(X = c("A", "B", "C"), + Number1 = c(50, 18, 11), + Number2 = c(-50, 137, 214)) + new_th2 <- data$th5 %>% + agg_by(agg_percentile(0.6, c("Number1", "Number2")), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th2), new_df2) + + new_df3 <- data.frame(X = c("A", "A", "B", "B", "B", "C", "C"), + Y = c("O", "P", "M", "N", "O", "N", "P" ), + Number1 = c(-5, -45, 86, 55, 99, -65, 0), + Number2 = c(6, 34, -6, 76, 34, -5, -76)) + new_th3 <- data$th6 %>% + agg_by(agg_percentile(0.3, c("Number1", "Number2")), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th3), new_df3) }) test_that("agg_count behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 %>% + count(string_col) + new_th1 <- data$th1 %>% + agg_by(agg_count("n"), "string_col") %>% + sort_by("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + count(col1, col2) + new_th2 <- data$th2 %>% + agg_by(agg_count("n"), c("col1", "col2")) %>% + sort_by(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + count(X1, X2, X3, X4) + new_th3 <- data$th3 %>% + agg_by(agg_count("n"), c("X1", "X2", "X3", "X4")) %>% + sort_by(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + count(bool_col) + new_th4 <- data$th4 %>% + agg_by(agg_count("n"), "bool_col") %>% + sort_by("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + count(X) + new_th5 <- data$th5 %>% + agg_by(agg_count("n"), "X") %>% + sort_by("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 %>% + count(X, Y) + new_th6 <- data$th6 %>% + agg_by(agg_count("n"), c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 3cb5ee7c510..039fda9027b 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -473,9 +473,32 @@ test_that("avg_by behaves as expected", { expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -# TODO: I think that the current behavior of wAvgBy() is wrong and needs to be updated test_that("w_avg_by behaves as expected", { data <- setup() + + new_tb1 <- data$df5 %>% + select(-Y) %>% + mutate(weights = Number1 * Number2) %>% + dplyr::group_by(X) %>% + summarise(Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + update("weights = Number1 * Number2") %>% + w_avg_by("weights", "X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + mutate(weights = Number1 * Number2) %>% + dplyr::group_by(X, Y) %>% + summarise(Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + update("weights = Number1 * Number2") %>% + w_avg_by("weights", c("X", "Y")) %>% + sort_by(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) test_that("median_by behaves as expected", { From d131aa71a96a3ee447fb27606acd5f1948669001 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 27 Jul 2023 12:31:11 -0500 Subject: [PATCH 26/73] Add table ops documentation, not hooked into R yet --- R/rdeephaven/NAMESPACE | 14 +- R/rdeephaven/R/table_handle_wrapper.R | 19 +- R/rdeephaven/R/table_ops.R | 193 +++++++++++++----- .../inst/tests/testthat/test_client_wrapper.R | 8 + R/rdeephaven/src/client.cpp | 14 +- 5 files changed, 181 insertions(+), 67 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 5f15e010dc0..6d30282d7e5 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -3,16 +3,10 @@ S3method(as.data.frame,TableHandle) S3method(as_arrow_table,TableHandle) S3method(as_tibble,TableHandle) -S3method(dh_merge,TableHandle) -S3method(drop_columns,TableHandle) S3method(head,TableHandle) S3method(print,TableHandle) -S3method(select,TableHandle) +S3method(rbind,TableHandle) S3method(tail,TableHandle) -S3method(update,TableHandle) -S3method(update_view,TableHandle) -S3method(view,TableHandle) -S3method(where,TableHandle) export(Aggregation) export(Client) export(ClientOptions) @@ -35,8 +29,6 @@ export(agg_w_avg) export(avg_by) export(count_by) export(cross_join) -export(dh_merge) -export(dh_ungroup) export(drop_columns) export(exact_join) export(first_by) @@ -48,11 +40,13 @@ export(median_by) export(min_by) export(natural_join) export(percentile_by) -export(sort_by) +export(select) +export(sort) export(std_by) export(sum_by) export(tail_by) export(ungroup) +export(update) export(update_view) export(var_by) export(view) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index c82af5fffa8..8e99e4baeb0 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -107,7 +107,7 @@ TableHandle <- R6Class("TableHandle", cloneable = FALSE, ) ) -### S3 METHODS +# EXISTING GENERICS THAT WE CAN SUPPORT #' @export print.TableHandle <- function(th, ...) { @@ -129,3 +129,20 @@ as_tibble.TableHandle <- function(th, ...) { as.data.frame.TableHandle <- function(th, ...) { th$to_data_frame() } + +#' @export +head.TableHandle <- function(th, n) { + verify_int("n", n) + return(TableHandle$new(th$internal_table_handle$head(n))) +} + +#' @export +tail.TableHandle <- function(th, n) { + verify_int("n", n) + return(TableHandle$new(th$internal_table_handle$tail(n))) +} + +#' @export +rbind.TableHandle <- function(th, sources) { + return(TableHandle$new(th$internal_table_handle$merge(sources))) +} \ No newline at end of file diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 095f8c41d63..80fdc4454cf 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -1,74 +1,102 @@ -### S3 GENERICS -# The following generics do not already exist in the dplyr suite, so we must define them in order to implement the -# corresponding methods for TableHandles, so that the Deephaven query language feels identical to the dplyr experience. - -#' @export -view <- function(x, ...) {UseMethod("view", x)} -#' @export -update_view <- function(x, ...) {UseMethod("update_view", x)} -#' @export -drop_columns <- function(x, ...) {UseMethod("drop_columns", x)} -#' @export -where <- function(x, ...) {UseMethod("where", x)} - -# TODO: figure this shit out -#' @export -dh_ungroup <- function(x, ...) {UseMethod("dh_ungroup", x)} -#' @export -dh_merge <- function(x, ...) {UseMethod("dh_merge", x)} - -### S3 METHODS (implemented generics) - -#' @export -select.TableHandle <- function(th, columns = character()) { +#' @name TableOps +#' @title Deephaven TableHandle operations +#' @description These TableHandle operations provide a dplyr-like interface for filtering, aggregating, and summarizing +#' data in Deephaven Tables living on the server. For large datasets, constructing queries with these operations before +#' pulling results into an R data frame will be more performant than first pulling a Deephaven Table into an R data frame +#' and using existing dplyr methods. Additionally, these operations seamlessly support real-time Deephaven Tables, and +#' the resulting downstream tables will be automatically updated on the server when the parent tables update. +NULL + +# FILTERING OPERATIONS + +#' @description +#' Creates a new in-memory table that includes one column for each argument. +#' @param columns A string or list of strings specifying the columns to view. +#' @export +select <- function(th, columns = character()) { verify_string_vector("columns", columns) TableHandle$new(th$internal_table_handle$select(columns)) } +#' @description +#' Creates a new formula table that includes one column for each argument. +#' @param columns A string or list of strings specifying the columns to view. +#' @return TableHandle reference to the new table. #' @export -view.TableHandle <- function(th, columns = character()) { +view <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$view(columns))) } +#' @description +#' Creates a new table containing a new in-memory column for each argument. +#' @param columns A string or list of strings specifying the formulas to create new columns. +#' @return TableHandle reference to the new table. #' @export -update.TableHandle <- function(th, columns = character()) { +update <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$update(columns))) } +#' @description +#' Creates a new formula table containing a new formula for each argument. +#' @param columns A string or list of strings specifying the formulas to create new columns. +#' @return TableHandle reference to the new table. #' @export -update_view.TableHandle <- function(th, columns = character()) { +update_view <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$update_view(columns))) } +#' @description +#' Creates a new table with the same size as this table, but omits any of the specified columns. +#' @param columns A string or list of strings specifying the column names to drop. +#' @return TableHandle reference to the new table. #' @export -drop_columns.TableHandle <- function(th, columns = character()) { +drop_columns <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$drop_columns(columns))) } +#' @description +#' Creates a new table only containing the rows that meet the specified condition. +#' @param condition A string specifying a conditional expression. +#' @return TableHandle reference to the new table. #' @export -where.TableHandle <- function(th, condition) { +where <- function(th, condition) { verify_string("condition", condition) return(TableHandle$new(th$internal_table_handle$where(condition))) } # AGGREGATION OPERATIONS +#' @description +#' Creates a new table containing grouping columns and grouped data, with column content grouped into arrays. +#' @param group_by_columns A string or list of strings specifying the columns to group by. +#' @return TableHandle reference to the new table. #' @export group_by <- function(th, group_by_columns = character()) { verify_string_vector("group_by_columns", group_by_columns) return(TableHandle$new(th$internal_table_handle$group_by(group_by_columns))) } +#' @description +#' Creates a new table in which array columns from the source table are unwrapped into separate rows. +#' This is the inverse of a `group_by()` aggregation. +#' @param group_by_columns A string or list of strings specifying the columns to ungroup by. +#' @return TableHandle reference to the new table. #' @export ungroup <- function(th, group_by_columns = character()) { verify_string_vector("group_by_columns", group_by_columns) return(TableHandle$new(th$internal_table_handle$ungroup(group_by_columns))) } +#' @description +#' Creates a new table containing grouping columns and grouped data, defined by the specified aggregation(s). +#' @param aggregations A Deephaven Aggregation or a list of Aggregations specifying the aggregations to perform on the data. +#' TODO: Link agg_* docs for more info +#' @param group_by_columns #' @param group_by_columns A string or list of strings specifying the columns to group by. +#' @return TableHandle reference to the new table. #' @export agg_by <- function(th, aggregations, group_by_columns = character()) { verify_internal_type("Aggregation", "aggregations", aggregations) @@ -78,18 +106,31 @@ agg_by <- function(th, aggregations, group_by_columns = character()) { return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, group_by_columns))) } +#' @description +#' Creates a new table which contains the first row of each distinct group. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export first_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$first_by(columns))) } +#' @description +#' Creates a new table which contains the last row of each distinct group. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export last_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$last_by(columns))) } +#' @description +#' Creates a new table which contains the first n rows of each distinct group. +#' @param n An integer specifying the number of rows to include for each group. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export head_by <- function(th, n, columns = character()) { verify_int("n", n) @@ -97,6 +138,11 @@ head_by <- function(th, n, columns = character()) { return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) } +#' @description +#' Creates a new table which contains the last n rows of each distinct group. +#' @param n An integer specifying the number of rows to include for each group. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export tail_by <- function(th, n, columns = character()) { verify_int("n", n) @@ -104,36 +150,61 @@ tail_by <- function(th, n, columns = character()) { return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) } +#' @description +#' Creates a new table which contains the columnwise minimum of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export min_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$min_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise maximum of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export max_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$max_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise sum of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export sum_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$sum_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise sum of absolute values of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export abs_sum_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise average of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export avg_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$avg_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise weighted average of each distinct group, only defined for numeric columns. +#' @param weight_column A numeric column to use for the weights. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export w_avg_by <- function(th, weight_column, columns = character()) { verify_string("weight_column", weight_column) @@ -141,24 +212,42 @@ w_avg_by <- function(th, weight_column, columns = character()) { return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) } +#' @description +#' Creates a new table which contains the columnwise median of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export median_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$median_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise variance of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export var_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$var_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise standard deviation of each distinct group, only defined for numeric columns. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export std_by <- function(th, columns = character()) { verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$std_by(columns))) } +#' @description +#' Creates a new table which contains the columnwise pth percentile of each distinct group, only defined for numeric columns. +#' @param percentile A float in [0, 1] specifying the percentile. The results will be the values in the source table +#' nearest to the pth percentile, and no interpolation or estimation will be performed. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export percentile_by <- function(th, percentile, columns = character()) { verify_proportion("percentile", percentile) @@ -166,25 +255,21 @@ percentile_by <- function(th, percentile, columns = character()) { return(TableHandle$new(th$internal_table_handle$percentile_by(percentile, columns))) } +#' @description +#' Creates a new table which contains the number of rows in each distinct group. +#' @param count_by_column A string specifying the name of the new count column. +#' @param columns A string or list of strings specifying the column names to group by. +#' @return TableHandle reference to the new table. #' @export -count_by <- function(th, count_by_column, columns = character()) { +count_by <- function(th, count_by_column = "n", columns = character()) { verify_string("count_by_column", count_by_column) verify_string_vector("columns", columns) return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) } -#' @export -sort_by <- function(th, columns, descending = FALSE) { - verify_string_vector("columns", columns) - verify_bool_vector("descending", descending) - if ((length(descending) > 1) && length(descending) != length(columns)) { - stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) - } - return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) -} - # JOIN OPERATIONS +# TODO: Figure out the right defaults here to make interpretation simple #' @export cross_join <- function(th, right_side, columns_to_match, columns_to_add) { verify_string_vector("columns_to_match", columns_to_match) @@ -193,6 +278,7 @@ cross_join <- function(th, right_side, columns_to_match, columns_to_add) { columns_to_match, columns_to_add))) } +# TODO: Document this well #' @export natural_join <- function(th, right_side, columns_to_match, columns_to_add) { verify_string_vector("columns_to_match", columns_to_match) @@ -201,6 +287,7 @@ natural_join <- function(th, right_side, columns_to_match, columns_to_add) { columns_to_match, columns_to_add))) } +# TODO: Document this well #' @export exact_join <- function(th, right_side, columns_to_match, columns_to_add) { verify_string_vector("columns_to_match", columns_to_match) @@ -211,20 +298,18 @@ exact_join <- function(th, right_side, columns_to_match, columns_to_add) { # MISC OPERATIONS +#' @description +#' Creates a new table with rows sorted by the values in each distinct group. +#' @param columns A string or list of strings specifying the column names to group by. +#' @param descending A boolean or list of booleans the same size as columns, specifying +#' whether the sort should be descending or not. Defaults to ascending sort. +#' @return TableHandle reference to the new table. #' @export -head.TableHandle <- function(th, n) { - verify_int("n", n) - return(TableHandle$new(th$internal_table_handle$head(n))) -} - -#' @export -tail.TableHandle <- function(th, n) { - verify_int("n", n) - return(TableHandle$new(th$internal_table_handle$tail(n))) +sort <- function(th, columns, descending = FALSE) { + verify_string_vector("columns", columns) + verify_bool_vector("descending", descending) + if ((length(descending) > 1) && length(descending) != length(columns)) { + stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) + } + return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) } - -#' @export -dh_merge.TableHandle <- function(th, key_column, sources) { - verify_string("key_column", key_column) - return(TableHandle$new(th$internal_table_handle$merge(key_column, sources))) -} \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index d424807ea99..d84fe5e81aa 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -108,6 +108,10 @@ test_that("open_table opens the correct table from the server", { expect_equal(client$open_table("table4")$to_data_frame(), th4$to_data_frame()) }) +# TODO: Test empty_table good inputs + +# TODO: Test time_table good inputs + test_that("run_script correctly runs a python script", { client_options <- ClientOptions$new() @@ -193,6 +197,10 @@ test_that("open_table fails nicely with bad inputs", { expect_error(client$open_table(c("I", "am", "string")), "'name' must be passed as a single string. Got a character vector of length 3 instead.") }) +# TODO: Test empty_table bad inputs + +# TODO: Test time_table bad inputs + test_that("run_script fails nicely with bad input types", { client_options <- ClientOptions$new() diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 0be1a4655cb..34a40387ec5 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -237,9 +237,9 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.tail(n)); }; - TableHandleWrapper* merge(std::string keyColumn, Rcpp::List sources) { + TableHandleWrapper* merge(Rcpp::List sources) { std::vector converted_sources = convertRcppListToVectorOfTypeTableHandle(sources); - return new TableHandleWrapper(internal_tbl_hdl.merge(keyColumn, converted_sources)); + return new TableHandleWrapper(internal_tbl_hdl.merge(converted_sources)); }; TableHandleWrapper* sort(std::vector columnSpecs, std::vector descending) { @@ -393,10 +393,20 @@ class ClientWrapper { return new TableHandleWrapper(internal_tbl_hdl_mngr.fetchTable(tableName)); } + /** + * Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. + * @param size Number of rows in the empty table. + */ TableHandleWrapper* emptyTable(int64_t size) { return new TableHandleWrapper(internal_tbl_hdl_mngr.emptyTable(size)); } + /** + * Creates a ticking table. + * @param startTimeNanos When the table should start ticking (in units of nanoseconds since the epoch). + * @param periodNanos Table ticking frequency (in nanoseconds). + * @return The TableHandle of the new table. + */ TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) { return new TableHandleWrapper(internal_tbl_hdl_mngr.timeTable(startTimeNanos, periodNanos)); }; From 36b757be42b2eaf417314a25b1c0546aea22325e Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 27 Jul 2023 12:45:50 -0500 Subject: [PATCH 27/73] Fix unit tests after renames --- .../inst/tests/testthat/test_agg_by.R | 148 +++++++++--------- .../testthat/test_table_handle_wrapper.R | 2 - .../inst/tests/testthat/test_table_ops.R | 88 +++++------ 3 files changed, 118 insertions(+), 120 deletions(-) diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index 4b07f3fedd2..b2f7023b79d 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -56,7 +56,7 @@ test_that("agg_first behaves as expected", { summarise(int_col = first(int_col)) new_th1 <- data$th1 %>% agg_by(agg_first("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -64,7 +64,7 @@ test_that("agg_first behaves as expected", { summarise(col3 = first(col3)) new_th2 <- data$th2 %>% agg_by(agg_first("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -72,7 +72,7 @@ test_that("agg_first behaves as expected", { summarise(X5 = first(X5), X6 = first(X6), X7 = first(X7), X8 = first(X8)) new_th3 <- data$th3 %>% agg_by(agg_first(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -80,7 +80,7 @@ test_that("agg_first behaves as expected", { summarise(time_col = first(time_col), int_col = first(int_col)) new_th4 <- data$th4 %>% agg_by(c(agg_first("time_col"), agg_first("int_col")), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -88,7 +88,7 @@ test_that("agg_first behaves as expected", { summarise(Number1 = first(Number1), Number2 = first(Number2)) new_th5 <- data$th5 %>% agg_by(agg_first(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -96,7 +96,7 @@ test_that("agg_first behaves as expected", { summarise(Number1 = first(Number1), Number2 = first(Number2)) new_th6 <- data$th6 %>% agg_by(agg_first(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -108,7 +108,7 @@ test_that("agg_last behaves as expected", { summarise(int_col = last(int_col)) new_th1 <- data$th1 %>% agg_by(agg_last("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -116,7 +116,7 @@ test_that("agg_last behaves as expected", { summarise(col3 = last(col3)) new_th2 <- data$th2 %>% agg_by(agg_last("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -124,7 +124,7 @@ test_that("agg_last behaves as expected", { summarise(X5 = last(X5), X6 = last(X6), X7 = last(X7), X8 = last(X8)) new_th3 <- data$th3 %>% agg_by(agg_last(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -132,7 +132,7 @@ test_that("agg_last behaves as expected", { summarise(time_col = last(time_col), int_col = last(int_col)) new_th4 <- data$th4 %>% agg_by(c(agg_last("time_col"), agg_last("int_col")), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -140,7 +140,7 @@ test_that("agg_last behaves as expected", { summarise(Number1 = last(Number1), Number2 = last(Number2)) new_th5 <- data$th5 %>% agg_by(agg_last(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -148,7 +148,7 @@ test_that("agg_last behaves as expected", { summarise(Number1 = last(Number1), Number2 = last(Number2)) new_th6 <- data$th6 %>% agg_by(agg_last(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -160,7 +160,7 @@ test_that("agg_min behaves as expected", { summarise(int_col = min(int_col)) new_th1 <- data$th1 %>% agg_by(agg_min("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -168,7 +168,7 @@ test_that("agg_min behaves as expected", { summarise(col3 = min(col3)) new_th2 <- data$th2 %>% agg_by(agg_min("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -176,7 +176,7 @@ test_that("agg_min behaves as expected", { summarise(X5 = min(X5), X6 = min(X6), X7 = min(X7), X8 = min(X8)) new_th3 <- data$th3 %>% agg_by(agg_min(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -184,7 +184,7 @@ test_that("agg_min behaves as expected", { summarise(time_col = min(time_col), int_col = min(int_col)) new_th4 <- data$th4 %>% agg_by(c(agg_min("time_col"), agg_min("int_col")), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -192,7 +192,7 @@ test_that("agg_min behaves as expected", { summarise(Number1 = min(Number1), Number2 = min(Number2)) new_th5 <- data$th5 %>% agg_by(agg_min(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -200,7 +200,7 @@ test_that("agg_min behaves as expected", { summarise(Number1 = min(Number1), Number2 = min(Number2)) new_th6 <- data$th6 %>% agg_by(agg_min(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -212,7 +212,7 @@ test_that("agg_max behaves as expected", { summarise(int_col = max(int_col)) new_th1 <- data$th1 %>% agg_by(agg_max("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -220,7 +220,7 @@ test_that("agg_max behaves as expected", { summarise(col3 = max(col3)) new_th2 <- data$th2 %>% agg_by(agg_max("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -228,7 +228,7 @@ test_that("agg_max behaves as expected", { summarise(X5 = max(X5), X6 = max(X6), X7 = max(X7), X8 = max(X8)) new_th3 <- data$th3 %>% agg_by(agg_max(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -236,7 +236,7 @@ test_that("agg_max behaves as expected", { summarise(time_col = max(time_col), int_col = max(int_col)) new_th4 <- data$th4 %>% agg_by(c(agg_max("time_col"), agg_max("int_col")), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -244,7 +244,7 @@ test_that("agg_max behaves as expected", { summarise(Number1 = max(Number1), Number2 = max(Number2)) new_th5 <- data$th5 %>% agg_by(agg_max(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -252,7 +252,7 @@ test_that("agg_max behaves as expected", { summarise(Number1 = max(Number1), Number2 = max(Number2)) new_th6 <- data$th6 %>% agg_by(agg_max(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -264,7 +264,7 @@ test_that("agg_sum behaves as expected", { summarise(int_col = sum(int_col)) new_th1 <- data$th1 %>% agg_by(agg_sum("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -272,7 +272,7 @@ test_that("agg_sum behaves as expected", { summarise(col3 = sum(col3)) new_th2 <- data$th2 %>% agg_by(agg_sum("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -280,7 +280,7 @@ test_that("agg_sum behaves as expected", { summarise(X5 = sum(X5), X6 = sum(X6), X7 = sum(X7), X8 = sum(X8)) new_th3 <- data$th3 %>% agg_by(agg_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -288,7 +288,7 @@ test_that("agg_sum behaves as expected", { summarise(int_col = sum(int_col)) new_th4 <- data$th4 %>% agg_by(agg_sum("int_col"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -296,7 +296,7 @@ test_that("agg_sum behaves as expected", { summarise(Number1 = sum(Number1), Number2 = sum(Number2)) new_th5 <- data$th5 %>% agg_by(agg_sum(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -304,7 +304,7 @@ test_that("agg_sum behaves as expected", { summarise(Number1 = sum(Number1), Number2 = sum(Number2)) new_th6 <- data$th6 %>% agg_by(agg_sum(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -316,7 +316,7 @@ test_that("agg_abs_sum behaves as expected", { summarise(int_col = sum(abs(int_col))) new_th1 <- data$th1 %>% agg_by(agg_abs_sum("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -324,7 +324,7 @@ test_that("agg_abs_sum behaves as expected", { summarise(col3 = sum(abs(col3))) new_th2 <- data$th2 %>% agg_by(agg_abs_sum("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -332,7 +332,7 @@ test_that("agg_abs_sum behaves as expected", { summarise(X5 = sum(abs(X5)), X6 = sum(abs(X6)), X7 = sum(abs(X7)), X8 = sum(abs(X8))) new_th3 <- data$th3 %>% agg_by(agg_abs_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -340,7 +340,7 @@ test_that("agg_abs_sum behaves as expected", { summarise(int_col = sum(abs(int_col))) new_th4 <- data$th4 %>% agg_by(agg_abs_sum("int_col"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -348,7 +348,7 @@ test_that("agg_abs_sum behaves as expected", { summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) new_th5 <- data$th5 %>% agg_by(agg_abs_sum(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -356,7 +356,7 @@ test_that("agg_abs_sum behaves as expected", { summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) new_th6 <- data$th6 %>% agg_by(agg_abs_sum(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -368,7 +368,7 @@ test_that("agg_avg behaves as expected", { summarise(int_col = mean(int_col)) new_th1 <- data$th1 %>% agg_by(agg_avg("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -376,7 +376,7 @@ test_that("agg_avg behaves as expected", { summarise(col3 = mean(col3)) new_th2 <- data$th2 %>% agg_by(agg_avg("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -384,7 +384,7 @@ test_that("agg_avg behaves as expected", { summarise(X5 = mean(X5), X6 = mean(X6), X7 = mean(X7), X8 = mean(X8)) new_th3 <- data$th3 %>% agg_by(agg_avg(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -392,7 +392,7 @@ test_that("agg_avg behaves as expected", { summarise(int_col = mean(int_col)) new_th4 <- data$th4 %>% agg_by(agg_avg("int_col"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -400,7 +400,7 @@ test_that("agg_avg behaves as expected", { summarise(Number1 = mean(Number1), Number2 = mean(Number2)) new_th5 <- data$th5 %>% agg_by(agg_avg(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -408,7 +408,7 @@ test_that("agg_avg behaves as expected", { summarise(Number1 = mean(Number1), Number2 = mean(Number2)) new_th6 <- data$th6 %>% agg_by(agg_avg(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -420,7 +420,7 @@ test_that("agg_w_avg behaves as expected", { summarise(int_col = weighted.mean(int_col, dbl_col)) new_th1 <- data$th1 %>% agg_by(agg_w_avg("dbl_col", "int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -428,7 +428,7 @@ test_that("agg_w_avg behaves as expected", { summarise(col3 = weighted.mean(col3, col1)) new_th2 <- data$th2 %>% agg_by(agg_w_avg("col1", "col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -437,7 +437,7 @@ test_that("agg_w_avg behaves as expected", { X7 = weighted.mean(X7, X9), X8 = weighted.mean(X8, X9)) new_th3 <- data$th3 %>% agg_by(agg_w_avg("X9", c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -445,7 +445,7 @@ test_that("agg_w_avg behaves as expected", { summarise(int_col = weighted.mean(int_col, int_col)) new_th4 <- data$th4 %>% agg_by(agg_w_avg("int_col", "int_col"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -456,7 +456,7 @@ test_that("agg_w_avg behaves as expected", { new_th5 <- data$th5 %>% update("weights = Number1 * Number2") %>% agg_by(agg_w_avg("weights", c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -466,7 +466,7 @@ test_that("agg_w_avg behaves as expected", { new_th6 <- data$th6 %>% update("weights = Number1 * Number2") %>% agg_by(agg_w_avg("weights", c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -478,7 +478,7 @@ test_that("agg_median behaves as expected", { summarise(int_col = median(int_col)) new_th1 <- data$th1 %>% agg_by(agg_median("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -486,7 +486,7 @@ test_that("agg_median behaves as expected", { summarise(col3 = median(col3)) new_th2 <- data$th2 %>% agg_by(agg_median("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -494,7 +494,7 @@ test_that("agg_median behaves as expected", { summarise(X5 = median(X5), X6 = median(X6), X7 = median(X7), X8 = median(X8)) new_th3 <- data$th3 %>% agg_by(agg_median(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -502,7 +502,7 @@ test_that("agg_median behaves as expected", { summarise(int_col = median(int_col)) new_th4 <- data$th4 %>% agg_by(agg_median("int_col"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -510,7 +510,7 @@ test_that("agg_median behaves as expected", { summarise(Number1 = median(Number1), Number2 = median(Number2)) new_th5 <- data$th5 %>% agg_by(agg_median(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -518,7 +518,7 @@ test_that("agg_median behaves as expected", { summarise(Number1 = median(Number1), Number2 = median(Number2)) new_th6 <- data$th6 %>% agg_by(agg_median(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -530,7 +530,7 @@ test_that("agg_var behaves as expected", { summarise(int_col = var(int_col)) new_th1 <- data$th1 %>% agg_by(agg_var("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -538,7 +538,7 @@ test_that("agg_var behaves as expected", { summarise(col3 = var(col3)) new_th2 <- data$th2 %>% agg_by(agg_var("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -546,7 +546,7 @@ test_that("agg_var behaves as expected", { summarise(X5 = var(X5), X6 = var(X6), X7 = var(X7), X8 = var(X8)) new_th3 <- data$th3 %>% agg_by(agg_var(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -554,7 +554,7 @@ test_that("agg_var behaves as expected", { summarise(int_col = var(int_col)) new_th4 <- data$th4 %>% agg_by(agg_var("int_col"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -562,7 +562,7 @@ test_that("agg_var behaves as expected", { summarise(Number1 = var(Number1), Number2 = var(Number2)) new_th5 <- data$th5 %>% agg_by(agg_var(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -570,7 +570,7 @@ test_that("agg_var behaves as expected", { summarise(Number1 = var(Number1), Number2 = var(Number2)) new_th6 <- data$th6 %>% agg_by(agg_var(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -582,7 +582,7 @@ test_that("agg_std behaves as expected", { summarise(int_col = sd(int_col)) new_th1 <- data$th1 %>% agg_by(agg_std("int_col"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% @@ -590,7 +590,7 @@ test_that("agg_std behaves as expected", { summarise(col3 = sd(col3)) new_th2 <- data$th2 %>% agg_by(agg_std("col3"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% @@ -598,7 +598,7 @@ test_that("agg_std behaves as expected", { summarise(X5 = sd(X5), X6 = sd(X6), X7 = sd(X7), X8 = sd(X8)) new_th3 <- data$th3 %>% agg_by(agg_std(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -606,7 +606,7 @@ test_that("agg_std behaves as expected", { summarise(int_col = sd(int_col)) new_th4 <- data$th4 %>% agg_by(agg_std("int_col"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% @@ -614,7 +614,7 @@ test_that("agg_std behaves as expected", { summarise(Number1 = sd(Number1), Number2 = sd(Number2)) new_th5 <- data$th5 %>% agg_by(agg_std(c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% @@ -622,7 +622,7 @@ test_that("agg_std behaves as expected", { summarise(Number1 = sd(Number1), Number2 = sd(Number2)) new_th6 <- data$th6 %>% agg_by(agg_std(c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) @@ -643,7 +643,7 @@ test_that("agg_percentile behaves as expected", { Number2 = c(-50, 137, 214)) new_th2 <- data$th5 %>% agg_by(agg_percentile(0.6, c("Number1", "Number2")), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th2), new_df2) new_df3 <- data.frame(X = c("A", "A", "B", "B", "B", "C", "C"), @@ -652,7 +652,7 @@ test_that("agg_percentile behaves as expected", { Number2 = c(6, 34, -6, 76, 34, -5, -76)) new_th3 <- data$th6 %>% agg_by(agg_percentile(0.3, c("Number1", "Number2")), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th3), new_df3) }) @@ -663,41 +663,41 @@ test_that("agg_count behaves as expected", { count(string_col) new_th1 <- data$th1 %>% agg_by(agg_count("n"), "string_col") %>% - sort_by("string_col") + sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% count(col1, col2) new_th2 <- data$th2 %>% agg_by(agg_count("n"), c("col1", "col2")) %>% - sort_by(c("col1", "col2")) + sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% count(X1, X2, X3, X4) new_th3 <- data$th3 %>% agg_by(agg_count("n"), c("X1", "X2", "X3", "X4")) %>% - sort_by(c("X1", "X2", "X3", "X4")) + sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% count(bool_col) new_th4 <- data$th4 %>% agg_by(agg_count("n"), "bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% count(X) new_th5 <- data$th5 %>% agg_by(agg_count("n"), "X") %>% - sort_by("X") + sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) new_tb6 <- data$df6 %>% count(X, Y) new_th6 <- data$th6 %>% agg_by(agg_count("n"), c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) }) \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 40e87caad95..9049bd28e50 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -56,8 +56,6 @@ test_that("nrow returns the correct number of rows", { expect_equal(data$th2$nrow(), nrow(data$df2)) expect_equal(data$th3$nrow(), nrow(data$df3)) expect_equal(data$th4$nrow(), nrow(data$df4)) - - # TODO: test nrow(data$th) when it is implemented }) test_that("bind_to_variable binds the table to a variable", { diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 039fda9027b..47048ab9c56 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -56,26 +56,26 @@ test_that("select behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - select(string_col) + dplyr::select(string_col) new_th1 <- data$th1 %>% select("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - select(col2, col3) + dplyr::select(col2, col3) new_th2 <- data$th2 %>% select(c("col2", "col3")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% - select(X1, X2) %>% + dplyr::select(X1, X2) %>% rename(first_col = X1) new_th3 <- data$th3 %>% select(c("first_col = X1", "X2")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% - select(int_col) %>% + dplyr::select(int_col) %>% mutate(new_col = int_col + 1, .keep = "none") new_th4 <- data$th4 %>% select("new_col = int_col + 1") @@ -83,7 +83,7 @@ test_that("select behaves as expected", { new_tb5 <- data$df5 %>% mutate(Number3 = Number1 * Number2) %>% - select(X, Number3) + dplyr::select(X, Number3) new_th5 <- data$th5 %>% select(c("X", "Number3 = Number1 * Number2")) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) @@ -93,26 +93,26 @@ test_that("view behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - select(string_col) + dplyr::select(string_col) new_th1 <- data$th1 %>% view("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - select(col2, col3) + dplyr::select(col2, col3) new_th2 <- data$th2 %>% view(c("col2", "col3")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% - select(X1, X2) %>% + dplyr::select(X1, X2) %>% rename(first_col = X1) new_th3 <- data$th3 %>% view(c("first_col = X1", "X2")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% - select(int_col) %>% + dplyr::select(int_col) %>% mutate(new_col = int_col + 1, .keep = "none") new_th4 <- data$th4 %>% view("new_col = int_col + 1") @@ -120,7 +120,7 @@ test_that("view behaves as expected", { new_tb5 <- data$df5 %>% mutate(Number3 = Number1 * Number2) %>% - select(X, Number3) + dplyr::select(X, Number3) new_th5 <- data$th5 %>% view(c("X", "Number3 = Number1 * Number2")) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) @@ -198,19 +198,19 @@ test_that("drop_columns behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% - select(-string_col) + dplyr::select(-string_col) new_th1 <- data$th1 %>% drop_columns("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% - select(-c(col1, col2)) + dplyr::select(-c(col1, col2)) new_th2 <- data$th2 %>% drop_columns(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% - select(-paste0("X", seq(2, 1000))) + dplyr::select(-paste0("X", seq(2, 1000))) new_th3 <- data$th3 %>% drop_columns(paste0("X", seq(2, 1000))) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) @@ -251,7 +251,7 @@ test_that("first_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% dplyr::group_by(X) %>% summarise(across(everything(), first)) new_th1 <- data$th5 %>% @@ -265,7 +265,7 @@ test_that("first_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% first_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -273,7 +273,7 @@ test_that("last_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% dplyr::group_by(X) %>% summarise(across(everything(), last)) new_th1 <- data$th5 %>% @@ -287,7 +287,7 @@ test_that("last_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% last_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -306,7 +306,7 @@ test_that("head_by behaves as expected", { slice_head(n=2) new_th2 <- data$th5 %>% head_by(2, c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -325,7 +325,7 @@ test_that("tail_by behaves as expected", { slice_tail(n=2) new_th2 <- data$th5 %>% tail_by(2, c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -354,7 +354,7 @@ test_that("min_by behaves as expected", { new_th3 <- data$th3 %>% update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% min_by(c("bool_col1", "bool_col2")) %>% - sort_by(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same + sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -363,7 +363,7 @@ test_that("min_by behaves as expected", { arrange(bool_col) new_th4 <- data$th4 %>% min_by("bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) }) @@ -392,7 +392,7 @@ test_that("max_by behaves as expected", { new_th3 <- data$th3 %>% update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% max_by(c("bool_col1", "bool_col2")) %>% - sort_by(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same + sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% @@ -401,7 +401,7 @@ test_that("max_by behaves as expected", { arrange(bool_col) new_th4 <- data$th4 %>% max_by("bool_col") %>% - sort_by("bool_col") + sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) }) @@ -409,7 +409,7 @@ test_that("sum_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% dplyr::group_by(X) %>% summarise(across(everything(), sum)) new_th1 <- data$th5 %>% @@ -423,7 +423,7 @@ test_that("sum_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% sum_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -431,7 +431,7 @@ test_that("abs_sum_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% dplyr::group_by(X) %>% summarise(across(everything(), sum)) @@ -447,7 +447,7 @@ test_that("abs_sum_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% abs_sum_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -455,7 +455,7 @@ test_that("avg_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% dplyr::group_by(X) %>% summarise(across(everything(), mean)) new_th1 <- data$th5 %>% @@ -469,7 +469,7 @@ test_that("avg_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% avg_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -477,7 +477,7 @@ test_that("w_avg_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% mutate(weights = Number1 * Number2) %>% dplyr::group_by(X) %>% summarise(Number1 = weighted.mean(Number1, weights), @@ -497,7 +497,7 @@ test_that("w_avg_by behaves as expected", { new_th2 <- data$th5 %>% update("weights = Number1 * Number2") %>% w_avg_by("weights", c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -505,7 +505,7 @@ test_that("median_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% dplyr::group_by(X) %>% summarise(across(everything(), median)) new_th1 <- data$th5 %>% @@ -519,7 +519,7 @@ test_that("median_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% median_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -527,7 +527,7 @@ test_that("var_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% dplyr::group_by(X) %>% summarise(across(everything(), var)) new_th1 <- data$th5 %>% @@ -541,7 +541,7 @@ test_that("var_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% var_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -549,7 +549,7 @@ test_that("std_by behaves as expected", { data <- setup() new_tb1 <- data$df5 %>% - select(-Y) %>% + dplyr::select(-Y) %>% dplyr::group_by(X) %>% summarise(across(everything(), sd)) new_th1 <- data$th5 %>% @@ -563,7 +563,7 @@ test_that("std_by behaves as expected", { arrange(X, Y) new_th2 <- data$th5 %>% std_by(c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) @@ -604,41 +604,41 @@ test_that("count_by behaves as expected", { count(X, Y) new_th2 <- data$th5 %>% count_by("n", c("X", "Y")) %>% - sort_by(c("X", "Y")) + sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) }) -test_that("sort_by behaves as expected", { +test_that("sort behaves as expected", { data <- setup() new_tb1 <- data$df1 %>% arrange(dbl_col) new_th1 <- data$th1 %>% - sort_by("dbl_col") + sort("dbl_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) new_tb2 <- data$df2 %>% arrange(desc(col3)) new_th2 <- data$th2 %>% - sort_by("col3", descending = TRUE) + sort("col3", descending = TRUE) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) new_tb3 <- data$df3 %>% arrange(X1, X2, X3, X4, X5) new_th3 <- data$th3 %>% - sort_by(c("X1", "X2", "X3", "X4", "X5")) + sort(c("X1", "X2", "X3", "X4", "X5")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) new_tb4 <- data$df4 %>% arrange(desc(bool_col), desc(int_col)) new_th4 <- data$th4 %>% - sort_by(c("bool_col", "int_col"), descending = TRUE) + sort(c("bool_col", "int_col"), descending = TRUE) expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) new_tb5 <- data$df5 %>% arrange(X, desc(Y), Number1) new_th5 <- data$th5 %>% - sort_by(c("X", "Y", "Number1"), descending = c(FALSE, TRUE, FALSE)) + sort(c("X", "Y", "Number1"), descending = c(FALSE, TRUE, FALSE)) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) }) From 3f916dfb3dde0aa929800315ea2edfb474cac6ea Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 27 Jul 2023 14:42:14 -0500 Subject: [PATCH 28/73] More unit tests --- R/rdeephaven/R/client_wrapper.R | 6 +++--- R/rdeephaven/R/helper_functions.R | 18 ++++++++++++++---- R/rdeephaven/R/table_handle_wrapper.R | 2 +- .../inst/tests/testthat/test_client_wrapper.R | 16 ++++++++++++++-- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index e42452b207c..5f8f7cd5662 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -58,7 +58,7 @@ Client <- R6Class("Client", cloneable = FALSE, #' @return TableHandle reference to the new table, which has not yet been named on the server. #' See TableHandle$bind_to_variable() for naming a new table on the server. empty_table = function(size) { - verify_int("size", size) + verify_int("size", size, type = "positive") return(TableHandle$new(private$internal_client$empty_table(size))) }, @@ -69,8 +69,8 @@ Client <- R6Class("Client", cloneable = FALSE, #' @return TableHandle reference to the new table, which has not yet been named on the server. #' See TableHandle$bind_to_variable() for naming a new table on the server. time_table = function(start_time_nanos, period_nanos) { - verify_int(start_time_nanos) - verify_int(period_nanos) + verify_int("start_time_nanos", start_time_nanos) + verify_int("period_nanos", period_nanos) return(TableHandle$new(private$internal_client$time_table(start_time_nanos, period_nanos))) }, diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 9205fa6d4b4..8cc3dd0c7d2 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -24,16 +24,26 @@ verify_bool_vector <- function(arg_name, bool_candidate) { } } -verify_int <- function(arg_name, int_candidate) { +verify_int <- function(arg_name, int_candidate, type = "any") { + if (type == "any") { + message = " an " + } else if (type == "nonnegative") { + message = " a non-negative " + } else if (type == "positive") { + message = " a positive " + } if (class(int_candidate)[[1]] != "numeric") { - stop(paste0("'", arg_name, "' must be an integer. Got an object of class ", first_class(int_candidate), " instead.")) + stop(paste0("'", arg_name, "' must be", message, "integer. Got an object of class ", first_class(int_candidate), " instead.")) } else if (all.equal(int_candidate, as.integer(int_candidate)) != TRUE) { # must use != TRUE as the result of all.equal() is not strictly boolean - stop(paste0("'", arg_name, "' must be an integer. Got a non-integer numeric type instead.")) + stop(paste0("'", arg_name, "' must be", message, "integer. Got a non-integer numeric type instead.")) } else if (length(int_candidate) != 1) { - stop(paste0("'", arg_name, "' must be an integer. Got a numeric vector of length ", length(int_candidate), " instead.")) + stop(paste0("'", arg_name, "' must be", message, "integer. Got a numeric vector of length ", length(int_candidate), " instead.")) + } + if (((type == "nonnegative") && (int_candidate < 0)) || ((type == "positive") && (int_candidate <= 0))) { + stop(paste0("'", arg_name, "' must be", message, "integer. Got ", int_candidate, " instead.")) } } diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 8e99e4baeb0..fe0bb7b04ac 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -145,4 +145,4 @@ tail.TableHandle <- function(th, n) { #' @export rbind.TableHandle <- function(th, sources) { return(TableHandle$new(th$internal_table_handle$merge(sources))) -} \ No newline at end of file +} diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index d84fe5e81aa..f78c1f6d2ab 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -108,7 +108,17 @@ test_that("open_table opens the correct table from the server", { expect_equal(client$open_table("table4")$to_data_frame(), th4$to_data_frame()) }) -# TODO: Test empty_table good inputs +test_that("empty_table correctly creates tables on the server", { + + client_options <- ClientOptions$new() + client <- Client$new(target="localhost:10000", client_options=client_options) + + th1 <- client$empty_table(10) %>% update("X = i") + expect_equal(th1$nrow(), 10) + + th2 <- client$empty_table(1234567) %>% update("X = i") + expect_equal(th2$nrow(), 1234567) +}) # TODO: Test time_table good inputs @@ -197,7 +207,9 @@ test_that("open_table fails nicely with bad inputs", { expect_error(client$open_table(c("I", "am", "string")), "'name' must be passed as a single string. Got a character vector of length 3 instead.") }) -# TODO: Test empty_table bad inputs +test_that("empty_table fails nicely with bad inputs", { + +}) # TODO: Test time_table bad inputs From 0b5ec03a78cd6ddd7659bab3513ddbae8dc4ba45 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 27 Jul 2023 15:22:53 -0500 Subject: [PATCH 29/73] Even more unit tests --- .../inst/tests/testthat/test_table_handle_wrapper.R | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 9049bd28e50..c1490a18730 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -31,9 +31,12 @@ setup <- function() { th3 <- client$import_table(df3) th4 <- client$import_table(df4) + # time table to test is_static() + th5 <- client$time_table(0, 1000000000) %>% update("X = ii") + return(list("client" = client, "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4)) + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5)) } ##### TESTING GOOD INPUTS ##### @@ -45,8 +48,7 @@ test_that("is_static returns the correct value", { expect_true(data$th2$is_static()) expect_true(data$th3$is_static()) expect_true(data$th4$is_static()) - - # TODO: test ticking tables when they can be created from R + expect_false(data$th5$is_static()) }) test_that("nrow returns the correct number of rows", { From f02200158f00c738733bfebafa1a480c82170b23 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 27 Jul 2023 15:45:47 -0500 Subject: [PATCH 30/73] Naming consistency in table operations --- R/rdeephaven/R/table_ops.R | 60 +++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 80fdc4454cf..5c19e363145 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -11,7 +11,7 @@ NULL #' @description #' Creates a new in-memory table that includes one column for each argument. -#' @param columns A string or list of strings specifying the columns to view. +#' @param by A string or list of strings specifying the columns to view. #' @export select <- function(th, columns = character()) { verify_string_vector("columns", columns) @@ -20,7 +20,7 @@ select <- function(th, columns = character()) { #' @description #' Creates a new formula table that includes one column for each argument. -#' @param columns A string or list of strings specifying the columns to view. +#' @param by A string or list of strings specifying the columns to view. #' @return TableHandle reference to the new table. #' @export view <- function(th, columns = character()) { @@ -30,7 +30,7 @@ view <- function(th, columns = character()) { #' @description #' Creates a new table containing a new in-memory column for each argument. -#' @param columns A string or list of strings specifying the formulas to create new columns. +#' @param by A string or list of strings specifying the formulas to create new columns. #' @return TableHandle reference to the new table. #' @export update <- function(th, columns = character()) { @@ -40,7 +40,7 @@ update <- function(th, columns = character()) { #' @description #' Creates a new formula table containing a new formula for each argument. -#' @param columns A string or list of strings specifying the formulas to create new columns. +#' @param by A string or list of strings specifying the formulas to create new columns. #' @return TableHandle reference to the new table. #' @export update_view <- function(th, columns = character()) { @@ -50,7 +50,7 @@ update_view <- function(th, columns = character()) { #' @description #' Creates a new table with the same size as this table, but omits any of the specified columns. -#' @param columns A string or list of strings specifying the column names to drop. +#' @param by A string or list of strings specifying the column names to drop. #' @return TableHandle reference to the new table. #' @export drop_columns <- function(th, columns = character()) { @@ -75,9 +75,9 @@ where <- function(th, condition) { #' @param group_by_columns A string or list of strings specifying the columns to group by. #' @return TableHandle reference to the new table. #' @export -group_by <- function(th, group_by_columns = character()) { - verify_string_vector("group_by_columns", group_by_columns) - return(TableHandle$new(th$internal_table_handle$group_by(group_by_columns))) +group_by <- function(th, columns = character()) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$group_by(columns))) } #' @description @@ -86,9 +86,9 @@ group_by <- function(th, group_by_columns = character()) { #' @param group_by_columns A string or list of strings specifying the columns to ungroup by. #' @return TableHandle reference to the new table. #' @export -ungroup <- function(th, group_by_columns = character()) { - verify_string_vector("group_by_columns", group_by_columns) - return(TableHandle$new(th$internal_table_handle$ungroup(group_by_columns))) +ungroup <- function(th, columns = character()) { + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$ungroup(columns))) } #' @description @@ -98,17 +98,17 @@ ungroup <- function(th, group_by_columns = character()) { #' @param group_by_columns #' @param group_by_columns A string or list of strings specifying the columns to group by. #' @return TableHandle reference to the new table. #' @export -agg_by <- function(th, aggregations, group_by_columns = character()) { +agg_by <- function(th, aggregations, columns = character()) { verify_internal_type("Aggregation", "aggregations", aggregations) - verify_string_vector("group_by_columns", group_by_columns) + verify_string_vector("columns", columns) aggregations = c(aggregations) unwrapped_aggregations = lapply(aggregations, strip_r6_wrapping_from_aggregation) - return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, group_by_columns))) + return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, columns))) } #' @description #' Creates a new table which contains the first row of each distinct group. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export first_by <- function(th, columns = character()) { @@ -118,7 +118,7 @@ first_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the last row of each distinct group. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export last_by <- function(th, columns = character()) { @@ -129,7 +129,7 @@ last_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the first n rows of each distinct group. #' @param n An integer specifying the number of rows to include for each group. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export head_by <- function(th, n, columns = character()) { @@ -141,7 +141,7 @@ head_by <- function(th, n, columns = character()) { #' @description #' Creates a new table which contains the last n rows of each distinct group. #' @param n An integer specifying the number of rows to include for each group. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export tail_by <- function(th, n, columns = character()) { @@ -152,7 +152,7 @@ tail_by <- function(th, n, columns = character()) { #' @description #' Creates a new table which contains the columnwise minimum of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export min_by <- function(th, columns = character()) { @@ -162,7 +162,7 @@ min_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the columnwise maximum of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export max_by <- function(th, columns = character()) { @@ -172,7 +172,7 @@ max_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the columnwise sum of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export sum_by <- function(th, columns = character()) { @@ -182,7 +182,7 @@ sum_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the columnwise sum of absolute values of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export abs_sum_by <- function(th, columns = character()) { @@ -192,7 +192,7 @@ abs_sum_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the columnwise average of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export avg_by <- function(th, columns = character()) { @@ -203,7 +203,7 @@ avg_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the columnwise weighted average of each distinct group, only defined for numeric columns. #' @param weight_column A numeric column to use for the weights. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export w_avg_by <- function(th, weight_column, columns = character()) { @@ -214,7 +214,7 @@ w_avg_by <- function(th, weight_column, columns = character()) { #' @description #' Creates a new table which contains the columnwise median of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export median_by <- function(th, columns = character()) { @@ -224,7 +224,7 @@ median_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the columnwise variance of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export var_by <- function(th, columns = character()) { @@ -234,7 +234,7 @@ var_by <- function(th, columns = character()) { #' @description #' Creates a new table which contains the columnwise standard deviation of each distinct group, only defined for numeric columns. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export std_by <- function(th, columns = character()) { @@ -246,7 +246,7 @@ std_by <- function(th, columns = character()) { #' Creates a new table which contains the columnwise pth percentile of each distinct group, only defined for numeric columns. #' @param percentile A float in [0, 1] specifying the percentile. The results will be the values in the source table #' nearest to the pth percentile, and no interpolation or estimation will be performed. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export percentile_by <- function(th, percentile, columns = character()) { @@ -258,7 +258,7 @@ percentile_by <- function(th, percentile, columns = character()) { #' @description #' Creates a new table which contains the number of rows in each distinct group. #' @param count_by_column A string specifying the name of the new count column. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @return TableHandle reference to the new table. #' @export count_by <- function(th, count_by_column = "n", columns = character()) { @@ -300,7 +300,7 @@ exact_join <- function(th, right_side, columns_to_match, columns_to_add) { #' @description #' Creates a new table with rows sorted by the values in each distinct group. -#' @param columns A string or list of strings specifying the column names to group by. +#' @param by A string or list of strings specifying the column names to group by. #' @param descending A boolean or list of booleans the same size as columns, specifying #' whether the sort should be descending or not. Defaults to ascending sort. #' @return TableHandle reference to the new table. From b158086b7891e6c4be1d8e576818473c963c7ad7 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Thu, 27 Jul 2023 17:16:02 -0500 Subject: [PATCH 31/73] Group_by and ungroup tests --- .../inst/tests/testthat/test_table_ops.R | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 47048ab9c56..7c99b20c055 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -50,8 +50,6 @@ setup <- function() { ##### TESTING GOOD INPUTS ##### -# TODO: Test all of the following with default inputs - test_that("select behaves as expected", { data <- setup() @@ -238,13 +236,36 @@ test_that("where behaves as expected", { expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) }) -# TODO: Test group_by and ungroup -test_that("group_by behaves as expected", { - data <- setup() -}) - -test_that("ungroup behaves as expected", { +test_that("group_by and ungroup behaves as expected", { data <- setup() + + # There is not a clean analog to group_by() in dplyr, so we evaluate + # correctness by evaluating that these functions behave as inverses. + # Easiest when grouping columns are first, otherwise we must also reorder. + + new_th1 <- data$th1 %>% + group_by("string_col") %>% + ungroup() %>% + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(data$th1 %>% sort("string_col"))) + + new_th3 <- data$th3 %>% + group_by(c("X1", "X2", "X3", "X4", "X5")) %>% + ungroup() %>% + sort(c("X1", "X2", "X3", "X4", "X5")) + expect_equal(as.data.frame(new_th3), as.data.frame(data$th3 %>% sort(c("X1", "X2", "X3", "X4", "X5")))) + + new_th5 <- data$th5 %>% + group_by("X") %>% + ungroup() %>% + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(data$th5 %>% sort("X"))) + + new_th6 <- data$th6 %>% + group_by(c("X", "Y")) %>% + ungroup() %>% + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(data$th6 %>% sort(c("X", "Y")))) }) test_that("first_by behaves as expected", { @@ -642,7 +663,7 @@ test_that("sort behaves as expected", { expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) }) -# TODO: Our definition of a cross join is significantly different from dplyr +# TODO: Test joins. Our join API is mildly confusing test_that("cross_join behaves as expected", { data <- setup() }) From 638486b0b87db22109c3aa757be56091d8c97d6b Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 28 Jul 2023 09:03:37 -0500 Subject: [PATCH 32/73] empty_table and time_table tests --- .../inst/tests/testthat/test_client_wrapper.R | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index f78c1f6d2ab..c0287e99550 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -208,10 +208,29 @@ test_that("open_table fails nicely with bad inputs", { }) test_that("empty_table fails nicely with bad inputs", { - + + client_options <- ClientOptions$new() + client <- Client$new(target="localhost:10000", client_options=client_options) + + expect_error(client$empty_table(0), "'size' must be a positive integer. Got 0 instead.") + expect_error(client$empty_table(-3), "'size' must be a positive integer. Got -3 instead.") + expect_error(client$empty_table(1.2345), "'size' must be a positive integer. Got a non-integer numeric type instead.") + expect_error(client$empty_table("hello!"), "'size' must be a positive integer. Got an object of class character instead.") + expect_error(client$empty_table(c(1, 2, 3, 4)), "'size' must be a positive integer. Got a numeric vector of length 4 instead.") }) -# TODO: Test time_table bad inputs +test_that("time_table fails nicely with bad inputs", { + + client_options <- ClientOptions$new() + client <- Client$new(target="localhost:10000", client_options=client_options) + + expect_error(client$time_table(1.23, 1000), "'start_time_nanos' must be an integer. Got a non-integer numeric type instead.") + expect_error(client$time_table(1000, 1.23), "'period_nanos' must be an integer. Got a non-integer numeric type instead.") + expect_error(client$time_table(c(1, 2, 3), 1000), "'start_time_nanos' must be an integer. Got a numeric vector of length 3 instead.") + expect_error(client$time_table(1000, c(1, 2, 3)), "'period_nanos' must be an integer. Got a numeric vector of length 3 instead.") + expect_error(client$time_table("hello!", 1000), "'start_time_nanos' must be an integer. Got an object of class character instead.") + expect_error(client$time_table(1000, "hello!"), "'period_nanos' must be an integer. Got an object of class character instead.") +}) test_that("run_script fails nicely with bad input types", { From d377f821e861f9d87478de43a339ff94960341ec Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 28 Jul 2023 09:52:13 -0500 Subject: [PATCH 33/73] Join unit tests --- .../inst/tests/testthat/test_table_ops.R | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 7c99b20c055..36d3132cd2d 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -663,15 +663,57 @@ test_that("sort behaves as expected", { expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) }) -# TODO: Test joins. Our join API is mildly confusing test_that("cross_join behaves as expected", { data <- setup() + + new_th1 <- data$th5 %>% + cross_join(data$th6, columns_to_match = character(), + columns_to_add = c("X_y = X", "Y_y = Y", "Number1_y = Number1", "Number2_y = Number2")) + new_tb1 <- data$df5 %>% + dplyr::cross_join(data$df6) %>% + rename(X = X.x, Y = Y.x, Number1 = Number1.x, Number2 = Number2.x, + X_y = X.y, Y_y = Y.y, Number1_y = Number1.y, Number2_y = Number2.y) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) }) test_that("natural_join behaves as expected", { data <- setup() + + new_th2 <- data$th6 %>% + drop_columns("Y") %>% + avg_by("X") + new_th1 <- data$th5 %>% + natural_join(new_th2, columns_to_match = "X", + columns_to_add = c("Number3 = Number1", "Number4 = Number2")) + + new_tb2 <- data$df6 %>% + dplyr::select(-Y) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), mean)) + new_tb1 <- data$df5 %>% + left_join(new_tb2, by = "X") %>% + rename(Number1 = Number1.x, Number2 = Number2.x, + Number3 = Number1.y, Number4 = Number2.y) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) }) +# TODO: Verify that inner_join is the analog of exact_join test_that("exact_join behaves as expected", { data <- setup() + + new_th2 <- data$th6 %>% + drop_columns("Y") %>% + avg_by("X") + new_th1 <- data$th5 %>% + exact_join(new_th2, columns_to_match = "X", + columns_to_add = c("Number3 = Number1", "Number4 = Number2")) + + new_tb2 <- data$df6 %>% + dplyr::select(-Y) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), mean)) + new_tb1 <- data$df5 %>% + inner_join(new_tb2, by = "X") %>% + rename(Number1 = Number1.x, Number2 = Number2.x, Number3 = Number1.y, Number4 = Number2.y) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) }) From ea1fb3bd5b00f2903a7831dbc319c47041e04fa1 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 28 Jul 2023 10:37:49 -0500 Subject: [PATCH 34/73] Add close method --- R/rdeephaven/R/client_wrapper.R | 7 +++++++ R/rdeephaven/src/client.cpp | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 5f8f7cd5662..74792cae784 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -107,6 +107,13 @@ Client <- R6Class("Client", cloneable = FALSE, run_script = function(script) { verify_string("script", script) private$internal_client$run_script(script) + }, + + #' @description + #' Closes the client connection and all associated state. Once this is called, no TableHandles pulled from + #' this client connection will remain valid. + close = function() { + private$internal_client$close() } ), private = list( diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 34a40387ec5..9053d30a54d 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -481,8 +481,20 @@ class ClientWrapper { return new TableHandleWrapper(new_tbl_hdl); } + /** + * Shuts down the Client and all associated state (GRPC connections, subscriptions, etc). + * This method is used if a caller wants to shut down Client state early. If it is not called, + * the shutdown actions will happen when this Client is destructed. The caller must not use any + * associated data structures (TableHandleManager, TableHandle, etc) after close() is called or + * after Client's destructor is invoked. If the caller tries to do so, the behavior is + * unspecified. + */ + void close() { + internal_client.close(); + } + private: - const deephaven::client::Client internal_client; + deephaven::client::Client internal_client; const deephaven::client::TableHandleManager internal_tbl_hdl_mngr = internal_client.getManager(); }; @@ -582,6 +594,7 @@ RCPP_MODULE(DeephavenInternalModule) { .method("run_script", &ClientWrapper::runScript) .method("new_arrow_array_stream_ptr", &ClientWrapper::newArrowArrayStreamPtr) .method("new_table_from_arrow_array_stream_ptr", &ClientWrapper::newTableFromArrowArrayStreamPtr) + .method("close", &ClientWrapper::close) ; } From 7e700942579ac6204de1ff67eac29e984a6a48e8 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 28 Jul 2023 11:16:51 -0500 Subject: [PATCH 35/73] Apply Tidyverse style guide --- R/rdeephaven/R/aggregate_wrapper.R | 112 +- R/rdeephaven/R/client_options_wrapper.R | 172 +-- R/rdeephaven/R/client_wrapper.R | 236 ++-- R/rdeephaven/R/exports.R | 2 +- R/rdeephaven/R/helper_functions.R | 101 +- R/rdeephaven/R/table_handle_wrapper.R | 176 ++- R/rdeephaven/R/table_ops.R | 154 +-- .../inst/tests/testthat/test_agg_by.R | 308 ++--- .../tests/testthat/test_aggregate_wrapper.R | 212 ++-- .../testthat/test_client_options_wrapper.R | 200 ++-- .../inst/tests/testthat/test_client_wrapper.R | 319 ++--- .../testthat/test_table_handle_wrapper.R | 258 ++-- .../inst/tests/testthat/test_table_ops.R | 1039 +++++++++-------- 13 files changed, 1790 insertions(+), 1499 deletions(-) diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R index fb12d337f11..234f1695f76 100644 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -1,98 +1,98 @@ #' @export -Aggregation <- R6Class("Aggregation", cloneable = FALSE, - public = list( - - #' @description - #' Create an Aggregation instance. - initialize = function(aggregation) { - if (class(aggregation) != "Rcpp_INTERNAL_Aggregate") { - stop("'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead.") - } - self$internal_aggregation <- aggregation - }, - - internal_aggregation = NULL - ) +Aggregation <- R6Class("Aggregation", + cloneable = FALSE, + public = list( + + #' @description + #' Create an Aggregation instance. + initialize = function(aggregation) { + if (class(aggregation) != "Rcpp_INTERNAL_Aggregate") { + stop("'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead.") + } + self$internal_aggregation <- aggregation + }, + internal_aggregation = NULL + ) ) ### All of the functions below return an instance of the above class #' @export -agg_first = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_first(columns))) +agg_first <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_first(columns))) } #' @export -agg_last = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_last(columns))) +agg_last <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_last(columns))) } #' @export -agg_min = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_min(columns))) +agg_min <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_min(columns))) } #' @export -agg_max = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_max(columns))) +agg_max <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_max(columns))) } #' @export -agg_sum = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_sum(columns))) +agg_sum <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_sum(columns))) } #' @export -agg_abs_sum = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_abs_sum(columns))) +agg_abs_sum <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_abs_sum(columns))) } #' @export -agg_avg = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_avg(columns))) +agg_avg <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_avg(columns))) } #' @export -agg_w_avg = function(weight_column, columns = character()) { - verify_string("weight_column", weight_column) - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) +agg_w_avg <- function(weight_column, columns = character()) { + verify_string("weight_column", weight_column) + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) } #' @export -agg_median = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_median(columns))) +agg_median <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_median(columns))) } #' @export -agg_var = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_var(columns))) +agg_var <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_var(columns))) } #' @export -agg_std = function(columns = character()) { - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_std(columns))) +agg_std <- function(columns = character()) { + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_std(columns))) } #' @export -agg_percentile = function(percentile, columns = character()) { - verify_proportion("percentile", percentile) - verify_string_vector("columns", columns) - return(Aggregation$new(INTERNAL_percentile(percentile, columns))) +agg_percentile <- function(percentile, columns = character()) { + verify_proportion("percentile", percentile) + verify_string_vector("columns", columns) + return(Aggregation$new(INTERNAL_percentile(percentile, columns))) } #' @export -agg_count = function(count_column) { - verify_string("count_column", count_column) - return(Aggregation$new(INTERNAL_count(count_column))) -} \ No newline at end of file +agg_count <- function(count_column) { + verify_string("count_column", count_column) + return(Aggregation$new(INTERNAL_count(count_column))) +} diff --git a/R/rdeephaven/R/client_options_wrapper.R b/R/rdeephaven/R/client_options_wrapper.R index 80c6ab93818..bc65fbea631 100644 --- a/R/rdeephaven/R/client_options_wrapper.R +++ b/R/rdeephaven/R/client_options_wrapper.R @@ -2,119 +2,119 @@ #' @description Client options provide a simple interface to the Deephaven server's authentication protocols. #' This makes it easy to connect to a Deephaven server with any flavor of authentication, and shields the API from #' any future changes to the underlying implementation. -#' +#' #' Currently, three different kinds of authentication that a Deephaven server might be using are suported: -#' +#' #' - "default": Default (or anonymous) authentication does not require any username or password. If #' running the Deephaven server locally, this is probably the kind of authentication needed. -#' +#' #' - "basic": Basic authentication requires a standard username and password pair. -#' +#' #' - "custom": Custom authentication requires general key-value pairs. -#' +#' #' In addition to setting the authentication parameters when connecting to a client, a console can be #' started in one of our supported server languages. Python and Groovy are currently supported, and the #' user must ensure that the server being connected to was started with support for the desired console language. -#' +#' #' @usage NULL #' @format NULL #' @docType class -#' +#' #' @examples -#' +#' #' # connect to a Deephaven server with a Python console running on "localhost:10000" using anonymous 'default' authentication #' client_options <- ClientOptions$new() -#' client <- Client$new(target="localhost:10000", client_options=client_options) -#' +#' client <- Client$new(target = "localhost:10000", client_options = client_options) +#' #' # connect to a secure Deephaven server with a Groovy console using username/password authentication #' client_options <- ClientOptions$new() -#' client_options$set_basic_authentication(username="user", password="p@ssw0rd123") +#' client_options$set_basic_authentication(username = "user", password = "p@ssw0rd123") #' client_options$set_session_type("groovy") -#' client <- Client$new(target="url/to/secure/server", client_options=client_options) +#' client <- Client$new(target = "url/to/secure/server", client_options = client_options) #' @export -ClientOptions <- R6Class("ClientOptions", cloneable = FALSE, - public = list( +ClientOptions <- R6Class("ClientOptions", + cloneable = FALSE, + public = list( - #' @description - #' Create a ClientOptions instance. This will default to using default (anonymous) authentication and a Python console. - initialize = function() { - self$internal_client_options <- new(INTERNAL_ClientOptions) - }, + #' @description + #' Create a ClientOptions instance. This will default to using default (anonymous) authentication and a Python console. + initialize = function() { + self$internal_client_options <- new(INTERNAL_ClientOptions) + }, - #' @description - #' Use default (anonymous) authentication. If running a Deephaven server locally, this is likely the kind of authentication needed. - set_default_authentication = function() { - self$internal_client_options$set_default_authentication() - }, + #' @description + #' Use default (anonymous) authentication. If running a Deephaven server locally, this is likely the kind of authentication needed. + set_default_authentication = function() { + self$internal_client_options$set_default_authentication() + }, - #' @description - #' Use basic (username/password based) authentication. - #' @param username Username of the account to use for authentication, supplied as a string. - #' @param password Password of the account, supplied as a string. - set_basic_authentication = function(username, password) { - verify_string("username", username) - verify_string("password", password) - self$internal_client_options$set_basic_authentication(username, password) - }, + #' @description + #' Use basic (username/password based) authentication. + #' @param username Username of the account to use for authentication, supplied as a string. + #' @param password Password of the account, supplied as a string. + set_basic_authentication = function(username, password) { + verify_string("username", username) + verify_string("password", password) + self$internal_client_options$set_basic_authentication(username, password) + }, - #' @description - #' Use custom (general key/value based) authentication. - #' @param auth_key Key to use for authentication, supplied as a string. - #' @param auth_value Value to use for authentication, supplied as a string. - set_custom_authentication = function(auth_key, auth_value) { - verify_string("auth_key", auth_key) - verify_string("auth_value", auth_value) - self$internal_client_options$set_custom_authentication(auth_key, auth_value) - }, + #' @description + #' Use custom (general key/value based) authentication. + #' @param auth_key Key to use for authentication, supplied as a string. + #' @param auth_value Value to use for authentication, supplied as a string. + set_custom_authentication = function(auth_key, auth_value) { + verify_string("auth_key", auth_key) + verify_string("auth_value", auth_value) + self$internal_client_options$set_custom_authentication(auth_key, auth_value) + }, - #' @description - #' Set the session type of the console (e.g., "python", "groovy", etc.). The session type must be supported on the server. - #' @param session_type Desired language of the console. "python", "groovy", etc. - set_session_type = function(session_type) { - verify_string("session_type", session_type) - self$internal_client_options$set_session_type(session_type) - }, + #' @description + #' Set the session type of the console (e.g., "python", "groovy", etc.). The session type must be supported on the server. + #' @param session_type Desired language of the console. "python", "groovy", etc. + set_session_type = function(session_type) { + verify_string("session_type", session_type) + self$internal_client_options$set_session_type(session_type) + }, - #' @description - #' Use the TLS protocol in authentication and subsequent communication. - #' @param root_certs Optional PEM-encoded certificate root for server connections. Defaults to system defaults. - use_tls = function(root_certs = "") { - verify_string("root_certs", root_certs) - self$internal_client_options$set_use_tls(TRUE) - self$internal_client_options$set_tls_root_certs(root_certs) - }, + #' @description + #' Use the TLS protocol in authentication and subsequent communication. + #' @param root_certs Optional PEM-encoded certificate root for server connections. Defaults to system defaults. + use_tls = function(root_certs = "") { + verify_string("root_certs", root_certs) + self$internal_client_options$set_use_tls(TRUE) + self$internal_client_options$set_tls_root_certs(root_certs) + }, - - #' Adds an int-valued option for the configuration of the underlying gRPC channels. - #' @param opt The option key. - #' @param val The option value. - add_int_option = function(opt, val) { - verify_string("opt", opt) - verify_int("val", val) - self$internal_client_options$add_int_option(opt, val) - }, - #' @description - #' Adds a string-valued option for the configuration of the underlying gRPC channels. - #' @param opt The option key. - #' @param val The option valiue. - add_string_option = function(opt, val) { - verify_string("opt", opt) - verify_string("val", val) - self$internal_client_options$add_string_option(opt, val) - }, + #' Adds an int-valued option for the configuration of the underlying gRPC channels. + #' @param opt The option key. + #' @param val The option value. + add_int_option = function(opt, val) { + verify_string("opt", opt) + verify_int("val", val) + self$internal_client_options$add_int_option(opt, val) + }, - #' @description - #' Adds an extra header with a constant name and value to be sent with every outgoing server request. - #' @param header_name The header name - #' @param header_value The header value - add_extra_header = function(header_name, header_value) { - verify_string("header_name", header_name) - verify_string("header_value", header_value) - self$internal_client_options$add_extra_header(header_name, header_value) - }, + #' @description + #' Adds a string-valued option for the configuration of the underlying gRPC channels. + #' @param opt The option key. + #' @param val The option valiue. + add_string_option = function(opt, val) { + verify_string("opt", opt) + verify_string("val", val) + self$internal_client_options$add_string_option(opt, val) + }, - internal_client_options = NULL - ) + #' @description + #' Adds an extra header with a constant name and value to be sent with every outgoing server request. + #' @param header_name The header name + #' @param header_value The header value + add_extra_header = function(header_name, header_value) { + verify_string("header_name", header_name) + verify_string("header_value", header_value) + self$internal_client_options$add_extra_header(header_name, header_value) + }, + internal_client_options = NULL + ) ) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 74792cae784..1f48bff5666 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -1,148 +1,142 @@ #' @title The Deephaven Client #' @description The Deephaven Client class is responsible for establishing and maintaining #' a connection to a running Deephaven server and facilitating basic server requests. -#' +#' #' @usage NULL #' @format NULL #' @docType class #' #' @examples -#' +#' #' # connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication #' client_options <- ClientOptions$new() -#' client <- Client$new(target="localhost:10000", client_options=client_options) -#' +#' client <- Client$new(target = "localhost:10000", client_options = client_options) +#' #' # open a table that already exists on the server #' new_table_handle1 <- client$open_table("table_on_the_server") -#' +#' #' # create a new dataframe, import onto the server, and retrieve a reference #' new_data_frame <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) #' new_table_handle2 <- client$import_table(new_data_frame) -#' +#' #' # run a python script on the server (default client options specify a Python console) #' client$run_script("print([i for i in range(10)])") #' @export -Client <- R6Class("Client", cloneable = FALSE, - public = list( - - #' @description - #' Connect to a running Deephaven server. - #' @param target The address of the Deephaven server. - #' @param client_options ClientOptions instance with the parameters needed to connect to the server. - #' See ?ClientOptions for more information. - initialize = function(target, client_options) { - verify_string("target", target) - if (first_class(client_options) != "ClientOptions") { - stop(paste("'client_options' should be a Deephaven ClientOptions object. Got an object of type", first_class(client_options), "instead.")) - } - private$internal_client <- new(INTERNAL_Client, target=target, - client_options=client_options$internal_client_options) - }, - - #' @description - #' Opens a table named 'name' from the server if it exists. - #' @param name Name of the table to open from the server, passed as a string. - #' @return TableHandle reference to the requested table. - open_table = function(name) { - verify_string("name", name) - if (!private$check_for_table(name)) { - stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) - } - return(TableHandle$new(private$internal_client$open_table(name))) - }, - - #' @description - #' Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. - #' @param size Number of rows in the empty table. - #' @return TableHandle reference to the new table, which has not yet been named on the server. - #' See TableHandle$bind_to_variable() for naming a new table on the server. - empty_table = function(size) { - verify_int("size", size, type = "positive") - return(TableHandle$new(private$internal_client$empty_table(size))) - }, - - #' @description - #' Creates a ticking table. - #' @param start_time_nanos When the table should start ticking (in units of nanoseconds since the epoch). - #' @param period_nanos Table ticking frequency (in nanoseconds). - #' @return TableHandle reference to the new table, which has not yet been named on the server. - #' See TableHandle$bind_to_variable() for naming a new table on the server. - time_table = function(start_time_nanos, period_nanos) { - verify_int("start_time_nanos", start_time_nanos) - verify_int("period_nanos", period_nanos) - return(TableHandle$new(private$internal_client$time_table(start_time_nanos, period_nanos))) - }, - - #' @description - #' Imports a new table to the Deephaven server. Note that this new table is not automatically bound to - #' a variable name on the server. See `?TableHandle` for more information. - #' @param table_object An R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow RecordBatchReader - #' containing the data to import to the server. - #' @return TableHandle reference to the new table. - import_table = function(table_object) { - table_object_class = class(table_object) - if (table_object_class[[1]] == "data.frame") { - return(TableHandle$new(private$df_to_dh_table(table_object))) - } - if (table_object_class[[1]] == "tbl_df") { - return(TableHandle$new(private$tibble_to_dh_table(table_object))) - } - else if (table_object_class[[1]] == "RecordBatchReader") { - return(TableHandle$new(private$rbr_to_dh_table(table_object))) - } - else if ((length(table_object_class) == 4 && - table_object_class[[1]] == "Table" && - table_object_class[[3]] == "ArrowObject")) { - return(TableHandle$new(private$arrow_to_dh_table(table_object))) - } - else { - stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], " instead.")) - } - }, +Client <- R6Class("Client", + cloneable = FALSE, + public = list( - #' @description - #' Runs a script on the server. The script must be in the language that the server console was started with. - #' @param script Code to be executed on the server, passed as a string. - run_script = function(script) { - verify_string("script", script) - private$internal_client$run_script(script) - }, + #' @description + #' Connect to a running Deephaven server. + #' @param target The address of the Deephaven server. + #' @param client_options ClientOptions instance with the parameters needed to connect to the server. + #' See ?ClientOptions for more information. + initialize = function(target, client_options) { + verify_string("target", target) + if (first_class(client_options) != "ClientOptions") { + stop(paste("'client_options' should be a Deephaven ClientOptions object. Got an object of type", first_class(client_options), "instead.")) + } + private$internal_client <- new(INTERNAL_Client, + target = target, + client_options = client_options$internal_client_options + ) + }, - #' @description - #' Closes the client connection and all associated state. Once this is called, no TableHandles pulled from - #' this client connection will remain valid. - close = function() { - private$internal_client$close() - } - ), - private = list( + #' @description + #' Opens a table named 'name' from the server if it exists. + #' @param name Name of the table to open from the server, passed as a string. + #' @return TableHandle reference to the requested table. + open_table = function(name) { + verify_string("name", name) + if (!private$check_for_table(name)) { + stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) + } + return(TableHandle$new(private$internal_client$open_table(name))) + }, - check_for_table = function(name) { - return(private$internal_client$check_for_table(name)) - }, - - rbr_to_dh_table = function(rbr) { - ptr = private$internal_client$new_arrow_array_stream_ptr() - rbr$export_to_c(ptr) - return(private$internal_client$new_table_from_arrow_array_stream_ptr(ptr)) - }, + #' @description + #' Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. + #' @param size Number of rows in the empty table. + #' @return TableHandle reference to the new table, which has not yet been named on the server. + #' See TableHandle$bind_to_variable() for naming a new table on the server. + empty_table = function(size) { + verify_int("size", size, type = "positive") + return(TableHandle$new(private$internal_client$empty_table(size))) + }, - arrow_to_dh_table = function(arrow_tbl) { - rbr = as_record_batch_reader(arrow_tbl) - return(private$rbr_to_dh_table(rbr)) - }, + #' @description + #' Creates a ticking table. + #' @param start_time_nanos When the table should start ticking (in units of nanoseconds since the epoch). + #' @param period_nanos Table ticking frequency (in nanoseconds). + #' @return TableHandle reference to the new table, which has not yet been named on the server. + #' See TableHandle$bind_to_variable() for naming a new table on the server. + time_table = function(start_time_nanos, period_nanos) { + verify_int("start_time_nanos", start_time_nanos) + verify_int("period_nanos", period_nanos) + return(TableHandle$new(private$internal_client$time_table(start_time_nanos, period_nanos))) + }, - tibble_to_dh_table = function(tibbl) { - arrow_tbl = arrow_table(tibbl) - return(private$arrow_to_dh_table(arrow_tbl)) - }, + #' @description + #' Imports a new table to the Deephaven server. Note that this new table is not automatically bound to + #' a variable name on the server. See `?TableHandle` for more information. + #' @param table_object An R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow RecordBatchReader + #' containing the data to import to the server. + #' @return TableHandle reference to the new table. + import_table = function(table_object) { + table_object_class <- class(table_object) + if (table_object_class[[1]] == "data.frame") { + return(TableHandle$new(private$df_to_dh_table(table_object))) + } + if (table_object_class[[1]] == "tbl_df") { + return(TableHandle$new(private$tibble_to_dh_table(table_object))) + } else if (table_object_class[[1]] == "RecordBatchReader") { + return(TableHandle$new(private$rbr_to_dh_table(table_object))) + } else if ((length(table_object_class) == 4 && + table_object_class[[1]] == "Table" && + table_object_class[[3]] == "ArrowObject")) { + return(TableHandle$new(private$arrow_to_dh_table(table_object))) + } else { + stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], " instead.")) + } + }, - df_to_dh_table = function(data_frame) { - arrow_tbl = arrow_table(data_frame) - return(private$arrow_to_dh_table(arrow_tbl)) - }, + #' @description + #' Runs a script on the server. The script must be in the language that the server console was started with. + #' @param script Code to be executed on the server, passed as a string. + run_script = function(script) { + verify_string("script", script) + private$internal_client$run_script(script) + }, - internal_client = NULL - ) + #' @description + #' Closes the client connection and all associated state. Once this is called, no TableHandles pulled from + #' this client connection will remain valid. + close = function() { + private$internal_client$close() + } + ), + private = list( + check_for_table = function(name) { + return(private$internal_client$check_for_table(name)) + }, + rbr_to_dh_table = function(rbr) { + ptr <- private$internal_client$new_arrow_array_stream_ptr() + rbr$export_to_c(ptr) + return(private$internal_client$new_table_from_arrow_array_stream_ptr(ptr)) + }, + arrow_to_dh_table = function(arrow_tbl) { + rbr <- as_record_batch_reader(arrow_tbl) + return(private$rbr_to_dh_table(rbr)) + }, + tibble_to_dh_table = function(tibbl) { + arrow_tbl <- arrow_table(tibbl) + return(private$arrow_to_dh_table(arrow_tbl)) + }, + df_to_dh_table = function(data_frame) { + arrow_tbl <- arrow_table(data_frame) + return(private$arrow_to_dh_table(arrow_tbl)) + }, + internal_client = NULL + ) ) diff --git a/R/rdeephaven/R/exports.R b/R/rdeephaven/R/exports.R index a36953209ed..0c34ac82bc4 100644 --- a/R/rdeephaven/R/exports.R +++ b/R/rdeephaven/R/exports.R @@ -2,4 +2,4 @@ #' @useDynLib rdeephaven, .registration = TRUE #' @importFrom Rcpp evalCpp -loadModule("DeephavenInternalModule", TRUE) \ No newline at end of file +loadModule("DeephavenInternalModule", TRUE) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 8cc3dd0c7d2..1ee77266071 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -1,79 +1,72 @@ first_class <- function(arg) class(arg)[[1]] verify_internal_type <- function(desired_type, arg_name, candidate) { - if ((first_class(candidate) == "list") && (any(lapply(candidate, first_class) != desired_type))) { - stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got a vector with at least one element that is not a Deephaven ", desired_type, " instead.")) - } - else if ((first_class(candidate) != "list") && (first_class(candidate) != desired_type)) { - stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got an object of class ", first_class(candidate), " instead.")) - } + if ((first_class(candidate) == "list") && (any(lapply(candidate, first_class) != desired_type))) { + stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got a vector with at least one element that is not a Deephaven ", desired_type, " instead.")) + } else if ((first_class(candidate) != "list") && (first_class(candidate) != desired_type)) { + stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got an object of class ", first_class(candidate), " instead.")) + } } verify_bool <- function(arg_name, bool_candidate) { - if (first_class(bool_candidate) != "logical") { - stop(paste0("'", arg_name, "' must be passed as a single boolean. Got an object of class ", first_class(bool_candidate), " instead.")) - } - else if (length(bool_candidate) != 1) { - stop(paste0("'", arg_name, "' must be passed as a single boolean. Got a boolean vector of length ", length(bool_candidate), " instead.")) - } + if (first_class(bool_candidate) != "logical") { + stop(paste0("'", arg_name, "' must be passed as a single boolean. Got an object of class ", first_class(bool_candidate), " instead.")) + } else if (length(bool_candidate) != 1) { + stop(paste0("'", arg_name, "' must be passed as a single boolean. Got a boolean vector of length ", length(bool_candidate), " instead.")) + } } verify_bool_vector <- function(arg_name, bool_candidate) { - if (first_class(bool_candidate) != "logical") { - stop(paste0("'", arg_name, "' must be passed as a boolean or a vector of booleans. Got an object of class ", first_class(bool_candidate), " instead.")) - } + if (first_class(bool_candidate) != "logical") { + stop(paste0("'", arg_name, "' must be passed as a boolean or a vector of booleans. Got an object of class ", first_class(bool_candidate), " instead.")) + } } verify_int <- function(arg_name, int_candidate, type = "any") { - if (type == "any") { - message = " an " - } else if (type == "nonnegative") { - message = " a non-negative " - } else if (type == "positive") { - message = " a positive " - } - if (class(int_candidate)[[1]] != "numeric") { - stop(paste0("'", arg_name, "' must be", message, "integer. Got an object of class ", first_class(int_candidate), " instead.")) - } - else if (all.equal(int_candidate, as.integer(int_candidate)) != TRUE) { - # must use != TRUE as the result of all.equal() is not strictly boolean - stop(paste0("'", arg_name, "' must be", message, "integer. Got a non-integer numeric type instead.")) - } - else if (length(int_candidate) != 1) { - stop(paste0("'", arg_name, "' must be", message, "integer. Got a numeric vector of length ", length(int_candidate), " instead.")) - } - if (((type == "nonnegative") && (int_candidate < 0)) || ((type == "positive") && (int_candidate <= 0))) { - stop(paste0("'", arg_name, "' must be", message, "integer. Got ", int_candidate, " instead.")) - } + if (type == "any") { + message <- " an " + } else if (type == "nonnegative") { + message <- " a non-negative " + } else if (type == "positive") { + message <- " a positive " + } + if (class(int_candidate)[[1]] != "numeric") { + stop(paste0("'", arg_name, "' must be", message, "integer. Got an object of class ", first_class(int_candidate), " instead.")) + } else if (all.equal(int_candidate, as.integer(int_candidate)) != TRUE) { + # must use != TRUE as the result of all.equal() is not strictly boolean + stop(paste0("'", arg_name, "' must be", message, "integer. Got a non-integer numeric type instead.")) + } else if (length(int_candidate) != 1) { + stop(paste0("'", arg_name, "' must be", message, "integer. Got a numeric vector of length ", length(int_candidate), " instead.")) + } + if (((type == "nonnegative") && (int_candidate < 0)) || ((type == "positive") && (int_candidate <= 0))) { + stop(paste0("'", arg_name, "' must be", message, "integer. Got ", int_candidate, " instead.")) + } } verify_proportion <- function(arg_name, prop_candidate) { - if (first_class(prop_candidate) != "numeric") { - stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got an object of class ", first_class(prop_candidate), " instead.")) - } - else if (length(prop_candidate) != 1) { - stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length ", length(prop_candidate), " instead.")) - } - else if ((prop_candidate < 0.0) || (prop_candidate > 1.0)) { - stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a value of ", prop_candidate, " instead.")) - } + if (first_class(prop_candidate) != "numeric") { + stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got an object of class ", first_class(prop_candidate), " instead.")) + } else if (length(prop_candidate) != 1) { + stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length ", length(prop_candidate), " instead.")) + } else if ((prop_candidate < 0.0) || (prop_candidate > 1.0)) { + stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a value of ", prop_candidate, " instead.")) + } } verify_string <- function(arg_name, string_candidate) { - if (first_class(string_candidate) != "character") { - stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", first_class(string_candidate), " instead.")) - } - else if (length(string_candidate) != 1) { - stop(paste0("'", arg_name, "' must be passed as a single string. Got a character vector of length ", length(string_candidate), " instead.")) - } + if (first_class(string_candidate) != "character") { + stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", first_class(string_candidate), " instead.")) + } else if (length(string_candidate) != 1) { + stop(paste0("'", arg_name, "' must be passed as a single string. Got a character vector of length ", length(string_candidate), " instead.")) + } } verify_string_vector <- function(arg_name, string_vector_candidate) { - if (first_class(string_vector_candidate) != "character") { - stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_vector_candidate), " instead.")) - } + if (first_class(string_vector_candidate) != "character") { + stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_vector_candidate), " instead.")) + } } strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { - return(r6_aggregation$internal_aggregation) + return(r6_aggregation$internal_aggregation) } diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index fe0bb7b04ac..737f1f85990 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -10,7 +10,7 @@ #' #' # connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication #' client_options <- ClientOptions$new() -#' client <- Client$new(target="localhost:10000", client_options=client_options) +#' client <- Client$new(target = "localhost:10000", client_options = client_options) #' #' # open a table that already exists on the server #' new_table_handle1 <- client$open_table("table_on_the_server") @@ -27,122 +27,120 @@ #' new_table_handle2$bind_to_variable("new_table") #' @export -TableHandle <- R6Class("TableHandle", cloneable = FALSE, - public = list( - - initialize = function(table_handle) { - if (first_class(table_handle) != "Rcpp_INTERNAL_TableHandle") { - stop("'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") - } - self$internal_table_handle <- table_handle - private$is_static_field <- self$internal_table_handle$is_static() - }, - - #' @description - #' Whether the table referenced by this TableHandle is static or not. - #' @return TRUE if the table is static, or FALSE if the table is ticking. - is_static = function() { - return(private$is_static_field) - }, - - #' @description - #' Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. - #' @return The number of rows in the table. - nrow = function() { - if(!private$is_static_field) { - stop("The number of rows is not yet supported for dynamic tables.") - } - return(self$internal_table_handle$num_rows()) - }, - - #' @description - #' Binds the table referenced by this TableHandle to a variable on the server, - #' enabling it to be accessed by that name from any Deephaven API. - #' @param name Name for this table on the server. - bind_to_variable = function(name) { - verify_string("name", name) - self$internal_table_handle$bind_to_variable(name) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. - #' @return A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. - to_arrow_record_batch_stream_reader = function() { - ptr = self$internal_table_handle$get_arrow_array_stream_ptr() - rbsr = RecordBatchStreamReader$import_from_c(ptr) - return(rbsr) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an Arrow Table. - #' @return A Table containing the data from the table referenced by this TableHandle. - to_arrow_table = function() { - rbsr = self$to_arrow_record_batch_stream_reader() - arrow_tbl = rbsr$read_table() - return(arrow_tbl) - }, - - #' @description - #' Imports the table referenced by this TableHandle into a dplyr Tibble. - #' @return A Tibble containing the data from the table referenced by this TableHandle. - to_tibble = function() { - rbsr = self$to_arrow_record_batch_stream_reader() - arrow_tbl = rbsr$read_table() - return(as_tibble(arrow_tbl)) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an R Data Frame. - #' @return A Data Frame containing the data from the table referenced by this TableHandle. - to_data_frame = function() { - arrow_tbl = self$to_arrow_table() - return(as.data.frame(as.data.frame(arrow_tbl))) # TODO: for some reason as.data.frame on arrow table returns a tibble, not a data frame - }, - - internal_table_handle = NULL - ), - private = list( - - is_static_field = NULL - ) +TableHandle <- R6Class("TableHandle", + cloneable = FALSE, + public = list( + initialize = function(table_handle) { + if (first_class(table_handle) != "Rcpp_INTERNAL_TableHandle") { + stop("'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") + } + self$internal_table_handle <- table_handle + private$is_static_field <- self$internal_table_handle$is_static() + }, + + #' @description + #' Whether the table referenced by this TableHandle is static or not. + #' @return TRUE if the table is static, or FALSE if the table is ticking. + is_static = function() { + return(private$is_static_field) + }, + + #' @description + #' Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. + #' @return The number of rows in the table. + nrow = function() { + if (!private$is_static_field) { + stop("The number of rows is not yet supported for dynamic tables.") + } + return(self$internal_table_handle$num_rows()) + }, + + #' @description + #' Binds the table referenced by this TableHandle to a variable on the server, + #' enabling it to be accessed by that name from any Deephaven API. + #' @param name Name for this table on the server. + bind_to_variable = function(name) { + verify_string("name", name) + self$internal_table_handle$bind_to_variable(name) + }, + + #' @description + #' Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. + #' @return A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. + to_arrow_record_batch_stream_reader = function() { + ptr <- self$internal_table_handle$get_arrow_array_stream_ptr() + rbsr <- RecordBatchStreamReader$import_from_c(ptr) + return(rbsr) + }, + + #' @description + #' Imports the table referenced by this TableHandle into an Arrow Table. + #' @return A Table containing the data from the table referenced by this TableHandle. + to_arrow_table = function() { + rbsr <- self$to_arrow_record_batch_stream_reader() + arrow_tbl <- rbsr$read_table() + return(arrow_tbl) + }, + + #' @description + #' Imports the table referenced by this TableHandle into a dplyr Tibble. + #' @return A Tibble containing the data from the table referenced by this TableHandle. + to_tibble = function() { + rbsr <- self$to_arrow_record_batch_stream_reader() + arrow_tbl <- rbsr$read_table() + return(as_tibble(arrow_tbl)) + }, + + #' @description + #' Imports the table referenced by this TableHandle into an R Data Frame. + #' @return A Data Frame containing the data from the table referenced by this TableHandle. + to_data_frame = function() { + arrow_tbl <- self$to_arrow_table() + return(as.data.frame(as.data.frame(arrow_tbl))) # TODO: for some reason as.data.frame on arrow table returns a tibble, not a data frame + }, + internal_table_handle = NULL + ), + private = list( + is_static_field = NULL + ) ) # EXISTING GENERICS THAT WE CAN SUPPORT #' @export print.TableHandle <- function(th, ...) { - cat("A Deephaven TableHandle:\n") - print(th$to_data_frame()) + cat("A Deephaven TableHandle:\n") + print(th$to_data_frame()) } #' @export as_arrow_table.TableHandle <- function(th, ...) { - th$to_arrow_table() + th$to_arrow_table() } #' @export as_tibble.TableHandle <- function(th, ...) { - th$to_tibble() + th$to_tibble() } #' @export as.data.frame.TableHandle <- function(th, ...) { - th$to_data_frame() + th$to_data_frame() } #' @export head.TableHandle <- function(th, n) { - verify_int("n", n) - return(TableHandle$new(th$internal_table_handle$head(n))) + verify_int("n", n) + return(TableHandle$new(th$internal_table_handle$head(n))) } #' @export tail.TableHandle <- function(th, n) { - verify_int("n", n) - return(TableHandle$new(th$internal_table_handle$tail(n))) + verify_int("n", n) + return(TableHandle$new(th$internal_table_handle$tail(n))) } #' @export rbind.TableHandle <- function(th, sources) { - return(TableHandle$new(th$internal_table_handle$merge(sources))) + return(TableHandle$new(th$internal_table_handle$merge(sources))) } diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 5c19e363145..55386094e02 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -14,8 +14,8 @@ NULL #' @param by A string or list of strings specifying the columns to view. #' @export select <- function(th, columns = character()) { - verify_string_vector("columns", columns) - TableHandle$new(th$internal_table_handle$select(columns)) + verify_string_vector("columns", columns) + TableHandle$new(th$internal_table_handle$select(columns)) } #' @description @@ -24,8 +24,8 @@ select <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export view <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$view(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$view(columns))) } #' @description @@ -34,8 +34,8 @@ view <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export update <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$update(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$update(columns))) } #' @description @@ -44,8 +44,8 @@ update <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export update_view <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$update_view(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$update_view(columns))) } #' @description @@ -54,8 +54,8 @@ update_view <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export drop_columns <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$drop_columns(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$drop_columns(columns))) } #' @description @@ -64,8 +64,8 @@ drop_columns <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export where <- function(th, condition) { - verify_string("condition", condition) - return(TableHandle$new(th$internal_table_handle$where(condition))) + verify_string("condition", condition) + return(TableHandle$new(th$internal_table_handle$where(condition))) } # AGGREGATION OPERATIONS @@ -76,8 +76,8 @@ where <- function(th, condition) { #' @return TableHandle reference to the new table. #' @export group_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$group_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$group_by(columns))) } #' @description @@ -87,8 +87,8 @@ group_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export ungroup <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$ungroup(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$ungroup(columns))) } #' @description @@ -99,11 +99,11 @@ ungroup <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export agg_by <- function(th, aggregations, columns = character()) { - verify_internal_type("Aggregation", "aggregations", aggregations) - verify_string_vector("columns", columns) - aggregations = c(aggregations) - unwrapped_aggregations = lapply(aggregations, strip_r6_wrapping_from_aggregation) - return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, columns))) + verify_internal_type("Aggregation", "aggregations", aggregations) + verify_string_vector("columns", columns) + aggregations <- c(aggregations) + unwrapped_aggregations <- lapply(aggregations, strip_r6_wrapping_from_aggregation) + return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, columns))) } #' @description @@ -112,8 +112,8 @@ agg_by <- function(th, aggregations, columns = character()) { #' @return TableHandle reference to the new table. #' @export first_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$first_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$first_by(columns))) } #' @description @@ -122,8 +122,8 @@ first_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export last_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$last_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$last_by(columns))) } #' @description @@ -133,9 +133,9 @@ last_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export head_by <- function(th, n, columns = character()) { - verify_int("n", n) - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) + verify_int("n", n) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) } #' @description @@ -145,9 +145,9 @@ head_by <- function(th, n, columns = character()) { #' @return TableHandle reference to the new table. #' @export tail_by <- function(th, n, columns = character()) { - verify_int("n", n) - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) + verify_int("n", n) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) } #' @description @@ -156,8 +156,8 @@ tail_by <- function(th, n, columns = character()) { #' @return TableHandle reference to the new table. #' @export min_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$min_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$min_by(columns))) } #' @description @@ -166,8 +166,8 @@ min_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export max_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$max_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$max_by(columns))) } #' @description @@ -176,8 +176,8 @@ max_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export sum_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$sum_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$sum_by(columns))) } #' @description @@ -186,8 +186,8 @@ sum_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export abs_sum_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) } #' @description @@ -196,8 +196,8 @@ abs_sum_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export avg_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$avg_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$avg_by(columns))) } #' @description @@ -207,9 +207,9 @@ avg_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export w_avg_by <- function(th, weight_column, columns = character()) { - verify_string("weight_column", weight_column) - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) + verify_string("weight_column", weight_column) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) } #' @description @@ -218,8 +218,8 @@ w_avg_by <- function(th, weight_column, columns = character()) { #' @return TableHandle reference to the new table. #' @export median_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$median_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$median_by(columns))) } #' @description @@ -228,8 +228,8 @@ median_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export var_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$var_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$var_by(columns))) } #' @description @@ -238,8 +238,8 @@ var_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export std_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$std_by(columns))) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$std_by(columns))) } #' @description @@ -250,9 +250,9 @@ std_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export percentile_by <- function(th, percentile, columns = character()) { - verify_proportion("percentile", percentile) - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$percentile_by(percentile, columns))) + verify_proportion("percentile", percentile) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$percentile_by(percentile, columns))) } #' @description @@ -262,9 +262,9 @@ percentile_by <- function(th, percentile, columns = character()) { #' @return TableHandle reference to the new table. #' @export count_by <- function(th, count_by_column = "n", columns = character()) { - verify_string("count_by_column", count_by_column) - verify_string_vector("columns", columns) - return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) + verify_string("count_by_column", count_by_column) + verify_string_vector("columns", columns) + return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) } # JOIN OPERATIONS @@ -272,28 +272,34 @@ count_by <- function(th, count_by_column = "n", columns = character()) { # TODO: Figure out the right defaults here to make interpretation simple #' @export cross_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) - return(TableHandle$new(th$internal_table_handle$cross_join(right_side$internal_table_handle, - columns_to_match, columns_to_add))) + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) + return(TableHandle$new(th$internal_table_handle$cross_join( + right_side$internal_table_handle, + columns_to_match, columns_to_add + ))) } # TODO: Document this well #' @export natural_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) - return(TableHandle$new(th$internal_table_handle$natural_join(right_side$internal_table_handle, - columns_to_match, columns_to_add))) + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) + return(TableHandle$new(th$internal_table_handle$natural_join( + right_side$internal_table_handle, + columns_to_match, columns_to_add + ))) } # TODO: Document this well #' @export exact_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) - return(TableHandle$new(th$internal_table_handle$exact_join(right_side$internal_table_handle, - columns_to_match, columns_to_add))) + verify_string_vector("columns_to_match", columns_to_match) + verify_string_vector("columns_to_add", columns_to_add) + return(TableHandle$new(th$internal_table_handle$exact_join( + right_side$internal_table_handle, + columns_to_match, columns_to_add + ))) } # MISC OPERATIONS @@ -306,10 +312,10 @@ exact_join <- function(th, right_side, columns_to_match, columns_to_add) { #' @return TableHandle reference to the new table. #' @export sort <- function(th, columns, descending = FALSE) { - verify_string_vector("columns", columns) - verify_bool_vector("descending", descending) - if ((length(descending) > 1) && length(descending) != length(columns)) { - stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) - } - return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) + verify_string_vector("columns", columns) + verify_bool_vector("descending", descending) + if ((length(descending) > 1) && length(descending) != length(columns)) { + stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) + } + return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) } diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index b2f7023b79d..d728b5d3a67 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -2,55 +2,66 @@ library(testthat) library(rdeephaven) setup <- function() { + df1 <- data.frame( + string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) + ) - df1 <- data.frame(string_col = c("I", "am", "a", "string", "column"), - int_col = c(0, 1, 2, 3, 4), - dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00)) - - df2 <- data.frame(col1 = rep(3.14, 100), - col2 = rep("hello!", 100), - col3 = rnorm(100)) - - df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) - - df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[250000], - bool_col = sample(c(TRUE, FALSE), 250000, TRUE), - int_col = sample(0:10000, 250000, TRUE)) - - df5 <- data.frame(X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), - Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), - Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), - Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214)) - - df6 <- data.frame(X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), - Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), - Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), - Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6)) - - # in order to test TableHandle, we need to have tables on the server that we know everything about. - # thus, we have to push these created tables to the server and get TableHandles to each of them. - # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() - - # set up client - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) - - # move dataframes to server and get TableHandles for testing - th1 <- client$import_table(df1) - th2 <- client$import_table(df2) - th3 <- client$import_table(df3) - th4 <- client$import_table(df4) - th5 <- client$import_table(df5) - th6 <- client$import_table(df6) - - return(list("client" = client, - "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6)) + df2 <- data.frame( + col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100) + ) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame( + time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE) + ) + + df5 <- data.frame( + X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), + Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), + Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214) + ) + + df6 <- data.frame( + X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), + Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), + Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), + Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) + ) + + # in order to test TableHandle, we need to have tables on the server that we know everything about. + # thus, we have to push these created tables to the server and get TableHandles to each of them. + # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() + + # set up client + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) + + # move dataframes to server and get TableHandles for testing + th1 <- client$import_table(df1) + th2 <- client$import_table(df2) + th3 <- client$import_table(df3) + th4 <- client$import_table(df4) + th5 <- client$import_table(df5) + th6 <- client$import_table(df6) + + return(list( + "client" = client, + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6 + )) } test_that("agg_first behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = first(int_col)) @@ -58,7 +69,7 @@ test_that("agg_first behaves as expected", { agg_by(agg_first("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = first(col3)) @@ -66,7 +77,7 @@ test_that("agg_first behaves as expected", { agg_by(agg_first("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = first(X5), X6 = first(X6), X7 = first(X7), X8 = first(X8)) @@ -74,7 +85,7 @@ test_that("agg_first behaves as expected", { agg_by(agg_first(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(time_col = first(time_col), int_col = first(int_col)) @@ -82,7 +93,7 @@ test_that("agg_first behaves as expected", { agg_by(c(agg_first("time_col"), agg_first("int_col")), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = first(Number1), Number2 = first(Number2)) @@ -90,7 +101,7 @@ test_that("agg_first behaves as expected", { agg_by(agg_first(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = first(Number1), Number2 = first(Number2)) @@ -98,11 +109,13 @@ test_that("agg_first behaves as expected", { agg_by(agg_first(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_last behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = last(int_col)) @@ -110,7 +123,7 @@ test_that("agg_last behaves as expected", { agg_by(agg_last("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = last(col3)) @@ -118,7 +131,7 @@ test_that("agg_last behaves as expected", { agg_by(agg_last("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = last(X5), X6 = last(X6), X7 = last(X7), X8 = last(X8)) @@ -126,7 +139,7 @@ test_that("agg_last behaves as expected", { agg_by(agg_last(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(time_col = last(time_col), int_col = last(int_col)) @@ -134,7 +147,7 @@ test_that("agg_last behaves as expected", { agg_by(c(agg_last("time_col"), agg_last("int_col")), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = last(Number1), Number2 = last(Number2)) @@ -142,7 +155,7 @@ test_that("agg_last behaves as expected", { agg_by(agg_last(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = last(Number1), Number2 = last(Number2)) @@ -150,11 +163,13 @@ test_that("agg_last behaves as expected", { agg_by(agg_last(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_min behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = min(int_col)) @@ -162,7 +177,7 @@ test_that("agg_min behaves as expected", { agg_by(agg_min("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = min(col3)) @@ -170,7 +185,7 @@ test_that("agg_min behaves as expected", { agg_by(agg_min("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = min(X5), X6 = min(X6), X7 = min(X7), X8 = min(X8)) @@ -178,7 +193,7 @@ test_that("agg_min behaves as expected", { agg_by(agg_min(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(time_col = min(time_col), int_col = min(int_col)) @@ -186,7 +201,7 @@ test_that("agg_min behaves as expected", { agg_by(c(agg_min("time_col"), agg_min("int_col")), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = min(Number1), Number2 = min(Number2)) @@ -194,7 +209,7 @@ test_that("agg_min behaves as expected", { agg_by(agg_min(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = min(Number1), Number2 = min(Number2)) @@ -202,11 +217,13 @@ test_that("agg_min behaves as expected", { agg_by(agg_min(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_max behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = max(int_col)) @@ -214,7 +231,7 @@ test_that("agg_max behaves as expected", { agg_by(agg_max("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = max(col3)) @@ -222,7 +239,7 @@ test_that("agg_max behaves as expected", { agg_by(agg_max("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = max(X5), X6 = max(X6), X7 = max(X7), X8 = max(X8)) @@ -230,7 +247,7 @@ test_that("agg_max behaves as expected", { agg_by(agg_max(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(time_col = max(time_col), int_col = max(int_col)) @@ -238,7 +255,7 @@ test_that("agg_max behaves as expected", { agg_by(c(agg_max("time_col"), agg_max("int_col")), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = max(Number1), Number2 = max(Number2)) @@ -246,7 +263,7 @@ test_that("agg_max behaves as expected", { agg_by(agg_max(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = max(Number1), Number2 = max(Number2)) @@ -254,11 +271,13 @@ test_that("agg_max behaves as expected", { agg_by(agg_max(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_sum behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = sum(int_col)) @@ -266,7 +285,7 @@ test_that("agg_sum behaves as expected", { agg_by(agg_sum("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = sum(col3)) @@ -274,7 +293,7 @@ test_that("agg_sum behaves as expected", { agg_by(agg_sum("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = sum(X5), X6 = sum(X6), X7 = sum(X7), X8 = sum(X8)) @@ -282,7 +301,7 @@ test_that("agg_sum behaves as expected", { agg_by(agg_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(int_col = sum(int_col)) @@ -290,7 +309,7 @@ test_that("agg_sum behaves as expected", { agg_by(agg_sum("int_col"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = sum(Number1), Number2 = sum(Number2)) @@ -298,7 +317,7 @@ test_that("agg_sum behaves as expected", { agg_by(agg_sum(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = sum(Number1), Number2 = sum(Number2)) @@ -306,11 +325,13 @@ test_that("agg_sum behaves as expected", { agg_by(agg_sum(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_abs_sum behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = sum(abs(int_col))) @@ -318,7 +339,7 @@ test_that("agg_abs_sum behaves as expected", { agg_by(agg_abs_sum("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = sum(abs(col3))) @@ -326,7 +347,7 @@ test_that("agg_abs_sum behaves as expected", { agg_by(agg_abs_sum("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = sum(abs(X5)), X6 = sum(abs(X6)), X7 = sum(abs(X7)), X8 = sum(abs(X8))) @@ -334,7 +355,7 @@ test_that("agg_abs_sum behaves as expected", { agg_by(agg_abs_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(int_col = sum(abs(int_col))) @@ -342,7 +363,7 @@ test_that("agg_abs_sum behaves as expected", { agg_by(agg_abs_sum("int_col"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) @@ -350,7 +371,7 @@ test_that("agg_abs_sum behaves as expected", { agg_by(agg_abs_sum(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) @@ -358,11 +379,13 @@ test_that("agg_abs_sum behaves as expected", { agg_by(agg_abs_sum(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_avg behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = mean(int_col)) @@ -370,7 +393,7 @@ test_that("agg_avg behaves as expected", { agg_by(agg_avg("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = mean(col3)) @@ -378,7 +401,7 @@ test_that("agg_avg behaves as expected", { agg_by(agg_avg("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = mean(X5), X6 = mean(X6), X7 = mean(X7), X8 = mean(X8)) @@ -386,7 +409,7 @@ test_that("agg_avg behaves as expected", { agg_by(agg_avg(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(int_col = mean(int_col)) @@ -394,7 +417,7 @@ test_that("agg_avg behaves as expected", { agg_by(agg_avg("int_col"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = mean(Number1), Number2 = mean(Number2)) @@ -402,7 +425,7 @@ test_that("agg_avg behaves as expected", { agg_by(agg_avg(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = mean(Number1), Number2 = mean(Number2)) @@ -410,11 +433,13 @@ test_that("agg_avg behaves as expected", { agg_by(agg_avg(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_w_avg behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = weighted.mean(int_col, dbl_col)) @@ -422,7 +447,7 @@ test_that("agg_w_avg behaves as expected", { agg_by(agg_w_avg("dbl_col", "int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = weighted.mean(col3, col1)) @@ -430,16 +455,18 @@ test_that("agg_w_avg behaves as expected", { agg_by(agg_w_avg("col1", "col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% - summarise(X5 = weighted.mean(X5, X9), X6 = weighted.mean(X6, X9), - X7 = weighted.mean(X7, X9), X8 = weighted.mean(X8, X9)) + summarise( + X5 = weighted.mean(X5, X9), X6 = weighted.mean(X6, X9), + X7 = weighted.mean(X7, X9), X8 = weighted.mean(X8, X9) + ) new_th3 <- data$th3 %>% agg_by(agg_w_avg("X9", c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(int_col = weighted.mean(int_col, int_col)) @@ -447,18 +474,20 @@ test_that("agg_w_avg behaves as expected", { agg_by(agg_w_avg("int_col", "int_col"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% mutate(weights = Number1 * Number2) %>% - summarise(Number1 = weighted.mean(Number1, weights), - Number2 = weighted.mean(Number2, weights)) + summarise( + Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights) + ) new_th5 <- data$th5 %>% update("weights = Number1 * Number2") %>% agg_by(agg_w_avg("weights", c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% mutate(weights = Number1 * Number2) %>% @@ -468,11 +497,13 @@ test_that("agg_w_avg behaves as expected", { agg_by(agg_w_avg("weights", c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_median behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = median(int_col)) @@ -480,7 +511,7 @@ test_that("agg_median behaves as expected", { agg_by(agg_median("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = median(col3)) @@ -488,7 +519,7 @@ test_that("agg_median behaves as expected", { agg_by(agg_median("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = median(X5), X6 = median(X6), X7 = median(X7), X8 = median(X8)) @@ -496,7 +527,7 @@ test_that("agg_median behaves as expected", { agg_by(agg_median(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(int_col = median(int_col)) @@ -504,7 +535,7 @@ test_that("agg_median behaves as expected", { agg_by(agg_median("int_col"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = median(Number1), Number2 = median(Number2)) @@ -512,7 +543,7 @@ test_that("agg_median behaves as expected", { agg_by(agg_median(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = median(Number1), Number2 = median(Number2)) @@ -520,11 +551,13 @@ test_that("agg_median behaves as expected", { agg_by(agg_median(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_var behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = var(int_col)) @@ -532,7 +565,7 @@ test_that("agg_var behaves as expected", { agg_by(agg_var("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = var(col3)) @@ -540,7 +573,7 @@ test_that("agg_var behaves as expected", { agg_by(agg_var("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = var(X5), X6 = var(X6), X7 = var(X7), X8 = var(X8)) @@ -548,7 +581,7 @@ test_that("agg_var behaves as expected", { agg_by(agg_var(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(int_col = var(int_col)) @@ -556,7 +589,7 @@ test_that("agg_var behaves as expected", { agg_by(agg_var("int_col"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = var(Number1), Number2 = var(Number2)) @@ -564,7 +597,7 @@ test_that("agg_var behaves as expected", { agg_by(agg_var(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = var(Number1), Number2 = var(Number2)) @@ -572,11 +605,13 @@ test_that("agg_var behaves as expected", { agg_by(agg_var(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_std behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::group_by(string_col) %>% summarise(int_col = sd(int_col)) @@ -584,7 +619,7 @@ test_that("agg_std behaves as expected", { agg_by(agg_std("int_col"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::group_by(col1, col2) %>% summarise(col3 = sd(col3)) @@ -592,7 +627,7 @@ test_that("agg_std behaves as expected", { agg_by(agg_std("col3"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::group_by(X1, X2, X3, X4) %>% summarise(X5 = sd(X5), X6 = sd(X6), X7 = sd(X7), X8 = sd(X8)) @@ -600,7 +635,7 @@ test_that("agg_std behaves as expected", { agg_by(agg_std(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% dplyr::group_by(bool_col) %>% summarise(int_col = sd(int_col)) @@ -608,7 +643,7 @@ test_that("agg_std behaves as expected", { agg_by(agg_std("int_col"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% dplyr::group_by(X) %>% summarise(Number1 = sd(Number1), Number2 = sd(Number2)) @@ -616,7 +651,7 @@ test_that("agg_std behaves as expected", { agg_by(agg_std(c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% dplyr::group_by(X, Y) %>% summarise(Number1 = sd(Number1), Number2 = sd(Number2)) @@ -624,80 +659,89 @@ test_that("agg_std behaves as expected", { agg_by(agg_std(c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + data$client$close() }) test_that("agg_percentile behaves as expected", { - # There is not a clean analog to agg_percentile in dplyr, so we create the # dataframes directly, and only make comparisons on deterministic data frames. - + data <- setup() - + new_df1 <- data.frame(int_col = 2) new_th1 <- data$th1 %>% agg_by(agg_percentile(0.4, "int_col")) expect_equal(as.data.frame(new_th1), new_df1) - - new_df2 <- data.frame(X = c("A", "B", "C"), - Number1 = c(50, 18, 11), - Number2 = c(-50, 137, 214)) + + new_df2 <- data.frame( + X = c("A", "B", "C"), + Number1 = c(50, 18, 11), + Number2 = c(-50, 137, 214) + ) new_th2 <- data$th5 %>% agg_by(agg_percentile(0.6, c("Number1", "Number2")), "X") %>% sort("X") expect_equal(as.data.frame(new_th2), new_df2) - - new_df3 <- data.frame(X = c("A", "A", "B", "B", "B", "C", "C"), - Y = c("O", "P", "M", "N", "O", "N", "P" ), - Number1 = c(-5, -45, 86, 55, 99, -65, 0), - Number2 = c(6, 34, -6, 76, 34, -5, -76)) + + new_df3 <- data.frame( + X = c("A", "A", "B", "B", "B", "C", "C"), + Y = c("O", "P", "M", "N", "O", "N", "P"), + Number1 = c(-5, -45, 86, 55, 99, -65, 0), + Number2 = c(6, 34, -6, 76, 34, -5, -76) + ) new_th3 <- data$th6 %>% agg_by(agg_percentile(0.3, c("Number1", "Number2")), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th3), new_df3) + + data$client$close() }) test_that("agg_count behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% count(string_col) new_th1 <- data$th1 %>% agg_by(agg_count("n"), "string_col") %>% sort("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% count(col1, col2) new_th2 <- data$th2 %>% agg_by(agg_count("n"), c("col1", "col2")) %>% sort(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% count(X1, X2, X3, X4) new_th3 <- data$th3 %>% agg_by(agg_count("n"), c("X1", "X2", "X3", "X4")) %>% sort(c("X1", "X2", "X3", "X4")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% count(bool_col) new_th4 <- data$th4 %>% agg_by(agg_count("n"), "bool_col") %>% sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% count(X) new_th5 <- data$th5 %>% agg_by(agg_count("n"), "X") %>% sort("X") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - + new_tb6 <- data$df6 %>% count(X, Y) new_th6 <- data$th6 %>% agg_by(agg_count("n"), c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) -}) \ No newline at end of file + + data$client$close() +}) diff --git a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R index 24099c4f824..a00b833976b 100644 --- a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R @@ -4,119 +4,189 @@ library(rdeephaven) ##### TESTING BAD INPUTS ##### test_that("trying to instantiate an Aggregation fails nicely", { - expect_error(Aggregation$new("hello"), - "'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead.") + expect_error( + Aggregation$new("hello"), + "'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead." + ) }) test_that("agg_min fails nicely when 'columns' is a bad type", { - expect_error(agg_min(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_min(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_min(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_min(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_max fails nicely when 'columns' is a bad type", { - expect_error(agg_max(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_max(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_max(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_max(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_sum fails nicely when 'columns' is a bad type", { - expect_error(agg_sum(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_sum(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_sum(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_sum(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_abs_sum fails nicely when 'columns' is a bad type", { - expect_error(agg_abs_sum(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_abs_sum(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_abs_sum(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_abs_sum(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_avg fails nicely when 'columns' is a bad type", { - expect_error(agg_avg(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_avg(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_avg(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_avg(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_w_avg fails nicely when 'weight_column' is a bad type", { - expect_error(agg_w_avg(5, "string"), - "'weight_column' must be passed as a single string. Got an object of class numeric instead.") - expect_error(agg_w_avg(TRUE, "string"), - "'weight_column' must be passed as a single string. Got an object of class logical instead.") - expect_error(agg_w_avg(c("Multiple", "strings", "bad"), "string"), - "'weight_column' must be passed as a single string. Got a character vector of length 3 instead.") + expect_error( + agg_w_avg(5, "string"), + "'weight_column' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + agg_w_avg(TRUE, "string"), + "'weight_column' must be passed as a single string. Got an object of class logical instead." + ) + expect_error( + agg_w_avg(c("Multiple", "strings", "bad"), "string"), + "'weight_column' must be passed as a single string. Got a character vector of length 3 instead." + ) }) test_that("agg_w_avg fails nicely when 'columns' is a bad type", { - expect_error(agg_w_avg("string", 5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_w_avg("string", TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_w_avg("string", 5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_w_avg("string", TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_var fails nicely when 'columns' is a bad type", { - expect_error(agg_var(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_var(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_var(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_var(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_std fails nicely when 'columns' is a bad type", { - expect_error(agg_std(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_std(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_std(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_std(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_first fails nicely when 'columns' is a bad type", { - expect_error(agg_first(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_first(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_first(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_first(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_last fails nicely when 'columns' is a bad type", { - expect_error(agg_last(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_last(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_last(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_last(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_median fails nicely when 'columns' is a bad type", { - expect_error(agg_median(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_median(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_median(5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_median(TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_percentile fails nicely when 'percentile' is bad", { - expect_error(agg_percentile("string", "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class character instead.") - expect_error(agg_percentile(TRUE, "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class logical instead.") - expect_error(agg_percentile(5, "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got a value of 5 instead.") - expect_error(agg_percentile(c(5,6,7,8), "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length 4 instead.") + expect_error( + agg_percentile("string", "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class character instead." + ) + expect_error( + agg_percentile(TRUE, "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class logical instead." + ) + expect_error( + agg_percentile(5, "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got a value of 5 instead." + ) + expect_error( + agg_percentile(c(5, 6, 7, 8), "string"), + "'percentile' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length 4 instead." + ) }) test_that("agg_percentile fails nicely when 'columns' is a bad type", { - expect_error(agg_percentile(0.5, 5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead.") - expect_error(agg_percentile(0.5, TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead.") + expect_error( + agg_percentile(0.5, 5), + "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + ) + expect_error( + agg_percentile(0.5, TRUE), + "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + ) }) test_that("agg_count fails nicely when 'count_column' is a bad type", { - expect_error(agg_count(5), - "'count_column' must be passed as a single string. Got an object of class numeric instead.") - expect_error(agg_count(TRUE), - "'count_column' must be passed as a single string. Got an object of class logical instead.") - expect_error(agg_count(c("Many", "strings")), - "'count_column' must be passed as a single string. Got a character vector of length 2 instead.") -}) \ No newline at end of file + expect_error( + agg_count(5), + "'count_column' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + agg_count(TRUE), + "'count_column' must be passed as a single string. Got an object of class logical instead." + ) + expect_error( + agg_count(c("Many", "strings")), + "'count_column' must be passed as a single string. Got a character vector of length 2 instead." + ) +}) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R index e5760b19a78..075f550d05b 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R @@ -4,122 +4,160 @@ library(rdeephaven) ##### TESTING GOOD INPUTS ##### test_that("initializing ClientOptions does not throw an error", { - expect_no_error(client_options <- ClientOptions$new()) + expect_no_error(client_options <- ClientOptions$new()) }) test_that("setting default authentication does not throw an error", { - - client_options <- ClientOptions$new() - expect_no_error(client_options$set_default_authentication()) + client_options <- ClientOptions$new() + expect_no_error(client_options$set_default_authentication()) }) test_that("setting basic authentication with string inputs does not throw an error", { - - client_options <- ClientOptions$new() - expect_no_error(client_options$set_basic_authentication("my_username", "my_password")) + client_options <- ClientOptions$new() + expect_no_error(client_options$set_basic_authentication("my_username", "my_password")) }) test_that("setting custom authentication with string inputs does not throw an error", { - - client_options <- ClientOptions$new() - expect_no_error(client_options$set_custom_authentication("my_key", "my_value")) + client_options <- ClientOptions$new() + expect_no_error(client_options$set_custom_authentication("my_key", "my_value")) }) test_that("setting session type to python does not throw an error", { - - client_options <- ClientOptions$new() - expect_no_error(client_options$set_session_type("python")) + client_options <- ClientOptions$new() + expect_no_error(client_options$set_session_type("python")) }) test_that("setting session type to groovy does not throw an error", { - - client_options <- ClientOptions$new() - expect_no_error(client_options$set_session_type("groovy")) + client_options <- ClientOptions$new() + expect_no_error(client_options$set_session_type("groovy")) }) ##### TESTING BAD INPUTS ##### test_that("setting basic authentication with bad input types fails nicely", { - - client_options <- ClientOptions$new() - expect_error(client_options$set_basic_authentication(12345, "my_password"), - "'username' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$set_basic_authentication("my_username", 12345), - "'password' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$set_basic_authentication(c("I", "am", "a", "string"), "my_password"), - "'username' must be passed as a single string. Got a character vector of length 4 instead.") - expect_error(client_options$set_basic_authentication("my_username", c("I", "am", "a", "string")), - "'password' must be passed as a single string. Got a character vector of length 4 instead.") + client_options <- ClientOptions$new() + expect_error( + client_options$set_basic_authentication(12345, "my_password"), + "'username' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$set_basic_authentication("my_username", 12345), + "'password' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$set_basic_authentication(c("I", "am", "a", "string"), "my_password"), + "'username' must be passed as a single string. Got a character vector of length 4 instead." + ) + expect_error( + client_options$set_basic_authentication("my_username", c("I", "am", "a", "string")), + "'password' must be passed as a single string. Got a character vector of length 4 instead." + ) }) test_that("setting custom authentication with bad input types fails nicely", { - - client_options <- ClientOptions$new() - expect_error(client_options$set_custom_authentication(12345, "my_auth_value"), - "'auth_key' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$set_custom_authentication("my_auth_key", 12345), - "'auth_value' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$set_custom_authentication(c("I", "am", "a", "string"), "my_auth_value"), - "'auth_key' must be passed as a single string. Got a character vector of length 4 instead.") - expect_error(client_options$set_custom_authentication("my_auth_key", c("I", "am", "a", "string")), - "'auth_value' must be passed as a single string. Got a character vector of length 4 instead.") + client_options <- ClientOptions$new() + expect_error( + client_options$set_custom_authentication(12345, "my_auth_value"), + "'auth_key' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$set_custom_authentication("my_auth_key", 12345), + "'auth_value' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$set_custom_authentication(c("I", "am", "a", "string"), "my_auth_value"), + "'auth_key' must be passed as a single string. Got a character vector of length 4 instead." + ) + expect_error( + client_options$set_custom_authentication("my_auth_key", c("I", "am", "a", "string")), + "'auth_value' must be passed as a single string. Got a character vector of length 4 instead." + ) }) test_that("setting bad session type fails nicely", { - - client_options <- ClientOptions$new() - expect_error(client_options$set_session_type(12345), - "'session_type' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$set_session_type(c("I", "am", "string")), - "'session_type' must be passed as a single string. Got a character vector of length 3 instead.") + client_options <- ClientOptions$new() + expect_error( + client_options$set_session_type(12345), + "'session_type' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$set_session_type(c("I", "am", "string")), + "'session_type' must be passed as a single string. Got a character vector of length 3 instead." + ) }) test_that("using tls with bad input type fails nicely", { - - client_options <- ClientOptions$new() - expect_error(client_options$use_tls(12345), - "'root_certs' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$use_tls(c("double", "string")), - "'root_certs' must be passed as a single string. Got a character vector of length 2 instead.") + client_options <- ClientOptions$new() + expect_error( + client_options$use_tls(12345), + "'root_certs' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$use_tls(c("double", "string")), + "'root_certs' must be passed as a single string. Got a character vector of length 2 instead." + ) }) test_that("add_int_option with bad types fails nicely", { - - client_options <- ClientOptions$new() - expect_error(client_options$add_int_option(12345, 12345), - "'opt' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$add_int_option(c("several", "strings"), 12345), - "'opt' must be passed as a single string. Got a character vector of length 2 instead.") - expect_error(client_options$add_int_option("option_key", "blah blah"), - "'val' must be an integer. Got an object of class character instead.") - expect_error(client_options$add_int_option("option_key", 12345.6789), - "'val' must be an integer. Got a non-integer numeric type instead.") - expect_error(client_options$add_int_option("option_key", c(1, 2, 3, 4, 5)), - "'val' must be an integer. Got a numeric vector of length 5 instead.") + client_options <- ClientOptions$new() + expect_error( + client_options$add_int_option(12345, 12345), + "'opt' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$add_int_option(c("several", "strings"), 12345), + "'opt' must be passed as a single string. Got a character vector of length 2 instead." + ) + expect_error( + client_options$add_int_option("option_key", "blah blah"), + "'val' must be an integer. Got an object of class character instead." + ) + expect_error( + client_options$add_int_option("option_key", 12345.6789), + "'val' must be an integer. Got a non-integer numeric type instead." + ) + expect_error( + client_options$add_int_option("option_key", c(1, 2, 3, 4, 5)), + "'val' must be an integer. Got a numeric vector of length 5 instead." + ) }) test_that("add_string_option with bad types fails nicely", { - - client_options <- ClientOptions$new() - expect_error(client_options$add_string_option(12345, "option_val"), - "'opt' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$add_string_option(c("several", "strings"), "option_val"), - "'opt' must be passed as a single string. Got a character vector of length 2 instead.") - expect_error(client_options$add_string_option("option_key", 12345), - "'val' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$add_string_option("option_key", c("several", "many", "strings")), - "'val' must be passed as a single string. Got a character vector of length 3 instead.") + client_options <- ClientOptions$new() + expect_error( + client_options$add_string_option(12345, "option_val"), + "'opt' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$add_string_option(c("several", "strings"), "option_val"), + "'opt' must be passed as a single string. Got a character vector of length 2 instead." + ) + expect_error( + client_options$add_string_option("option_key", 12345), + "'val' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$add_string_option("option_key", c("several", "many", "strings")), + "'val' must be passed as a single string. Got a character vector of length 3 instead." + ) }) test_that("add_extra_header with bad types fails nicely", { - - client_options <- ClientOptions$new() - expect_error(client_options$add_extra_header(12345, "header_value"), - "'header_name' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$add_extra_header(c("several", "strings"), "header_value"), - "'header_name' must be passed as a single string. Got a character vector of length 2 instead.") - expect_error(client_options$add_extra_header("header_name", 12345), - "'header_value' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client_options$add_extra_header("header_name", c("several", "many", "strings")), - "'header_value' must be passed as a single string. Got a character vector of length 3 instead.") -}) \ No newline at end of file + client_options <- ClientOptions$new() + expect_error( + client_options$add_extra_header(12345, "header_value"), + "'header_name' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$add_extra_header(c("several", "strings"), "header_value"), + "'header_name' must be passed as a single string. Got a character vector of length 2 instead." + ) + expect_error( + client_options$add_extra_header("header_name", 12345), + "'header_value' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client_options$add_extra_header("header_name", c("several", "many", "strings")), + "'header_value' must be passed as a single string. Got a character vector of length 3 instead." + ) +}) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index c0287e99550..682f9eacdd1 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -2,83 +2,97 @@ library(testthat) library(rdeephaven) setup <- function() { - - df1 <- data.frame(string_col = c("I", "am", "a", "string", "column"), - int_col = c(0, 1, 2, 3, 4), - dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00)) - - df2 <- data.frame(col1 = rep(3.14, 100), - col2 = rep("hello!", 100), - col3 = rnorm(100)) - - df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) - - df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[250000], - bool_col = sample(c(TRUE, FALSE), 250000, TRUE), - int_col = sample(0:10000, 250000, TRUE)) - - return(list("df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4)) + df1 <- data.frame( + string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) + ) + + df2 <- data.frame( + col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100) + ) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame( + time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE) + ) + + return(list("df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4)) } ##### TESTING GOOD INPUTS ##### test_that("client connection works in the simple case of anonymous authentication", { + # assumes correctness of client options + client_options <- ClientOptions$new() - # assumes correctness of client options - client_options <- ClientOptions$new() + # TODO: assumes server is actually running on localhost:10000, this is probably bad for CI + expect_no_error(client <- Client$new(target = "localhost:10000", client_options = client_options)) - # TODO: assumes server is actually running on localhost:10000, this is probably bad for CI - expect_no_error(client <- Client$new(target="localhost:10000", client_options=client_options)) + client$close() }) # All of the following tests assume the correctness of Client$new(...) to make the connection. test_that("import_table does not fail with data frame inputs of simple column types", { - data <- setup() + data <- setup() + + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + expect_no_error(client$import_table(data$df1)) + expect_no_error(client$import_table(data$df2)) + expect_no_error(client$import_table(data$df3)) + expect_no_error(client$import_table(data$df4)) - expect_no_error(client$import_table(data$df1)) - expect_no_error(client$import_table(data$df2)) - expect_no_error(client$import_table(data$df3)) - expect_no_error(client$import_table(data$df4)) + client$close() }) test_that("import_table does not fail with tibble inputs of simple column types", { - data <- setup() + data <- setup() + + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + expect_no_error(client$import_table(as_tibble(data$df1))) + expect_no_error(client$import_table(as_tibble(data$df2))) + expect_no_error(client$import_table(as_tibble(data$df3))) + expect_no_error(client$import_table(as_tibble(data$df4))) - expect_no_error(client$import_table(as_tibble(data$df1))) - expect_no_error(client$import_table(as_tibble(data$df2))) - expect_no_error(client$import_table(as_tibble(data$df3))) - expect_no_error(client$import_table(as_tibble(data$df4))) + client$close() }) test_that("import_table does not fail with arrow table inputs of simple column types", { - data <- setup() + data <- setup() + + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + expect_no_error(client$import_table(arrow_table(data$df1))) + expect_no_error(client$import_table(arrow_table(data$df2))) + expect_no_error(client$import_table(arrow_table(data$df3))) + expect_no_error(client$import_table(arrow_table(data$df4))) - expect_no_error(client$import_table(arrow_table(data$df1))) - expect_no_error(client$import_table(arrow_table(data$df2))) - expect_no_error(client$import_table(arrow_table(data$df3))) - expect_no_error(client$import_table(arrow_table(data$df4))) + client$close() }) test_that("import_table does not fail with record batch reader inputs of simple column types", { - data <- setup() + data <- setup() + + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df1)))) + expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df2)))) + expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df3)))) + expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df4)))) - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df1)))) - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df2)))) - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df3)))) - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df4)))) + client$close() }) # The following tests additionally assume the correctness of client$import_table(...) AND table_handle$bind_to_variable(), @@ -86,49 +100,51 @@ test_that("import_table does not fail with record batch reader inputs of simple # Additionally, we assume the correctness of table_handle$to_data_frame() to make concrete comparisons. test_that("open_table opens the correct table from the server", { - data <- setup() + data <- setup() - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) + + th1 <- client$import_table(data$df1) + th1$bind_to_variable("table1") + expect_equal(client$open_table("table1")$to_data_frame(), th1$to_data_frame()) - th1 <- client$import_table(data$df1) - th1$bind_to_variable("table1") - expect_equal(client$open_table("table1")$to_data_frame(), th1$to_data_frame()) + th2 <- client$import_table(data$df2) + th2$bind_to_variable("table2") + expect_equal(client$open_table("table2")$to_data_frame(), th2$to_data_frame()) - th2 <- client$import_table(data$df2) - th2$bind_to_variable("table2") - expect_equal(client$open_table("table2")$to_data_frame(), th2$to_data_frame()) + th3 <- client$import_table(data$df3) + th3$bind_to_variable("table3") + expect_equal(client$open_table("table3")$to_data_frame(), th3$to_data_frame()) - th3 <- client$import_table(data$df3) - th3$bind_to_variable("table3") - expect_equal(client$open_table("table3")$to_data_frame(), th3$to_data_frame()) + th4 <- client$import_table(data$df4) + th4$bind_to_variable("table4") + expect_equal(client$open_table("table4")$to_data_frame(), th4$to_data_frame()) - th4 <- client$import_table(data$df4) - th4$bind_to_variable("table4") - expect_equal(client$open_table("table4")$to_data_frame(), th4$to_data_frame()) + client$close() }) test_that("empty_table correctly creates tables on the server", { - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) - + client <- Client$new(target = "localhost:10000", client_options = client_options) + th1 <- client$empty_table(10) %>% update("X = i") expect_equal(th1$nrow(), 10) - + th2 <- client$empty_table(1234567) %>% update("X = i") expect_equal(th2$nrow(), 1234567) + + client$close() }) # TODO: Test time_table good inputs test_that("run_script correctly runs a python script", { + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) - - expect_no_error(client$run_script( -' + expect_no_error(client$run_script( + ' from deephaven import new_table from deephaven.column import string_col, int_col @@ -137,106 +153,125 @@ string_col("Name_String_Col", ["Data String 1", "Data String 2", "Data String 3" int_col("Name_Int_Col", [44, 55, 66]) ]) ' - )) + )) + + expect_no_error(client$open_table("static_table_from_python_script")) - expect_no_error(client$open_table("static_table_from_python_script")) + client$close() }) ##### TESTING BAD INPUTS ##### test_that("client connection fails nicely with bad target but good client_options", { + # assumes correctness of client options + client_options <- ClientOptions$new() - # assumes correctness of client options - client_options <- ClientOptions$new() - - # TODO: Bad address needs better error handling from the R side - expect_error(client <- Client$new(target="bad address", client_options=client_options)) - expect_error(client <- Client$new(target=12345, client_options=client_options), - "'target' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client <- Client$new(target=c("hello", "my", "name", "is"), client_options=client_options), - "'target' must be passed as a single string. Got a character vector of length 4 instead.") + # TODO: Bad address needs better error handling from the R side + expect_error(client <- Client$new(target = "bad address", client_options = client_options)) + expect_error( + client <- Client$new(target = 12345, client_options = client_options), + "'target' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + client <- Client$new(target = c("hello", "my", "name", "is"), client_options = client_options), + "'target' must be passed as a single string. Got a character vector of length 4 instead." + ) }) test_that("client connection fails nicely with good target but bad client_options", { - - # TODO: these all assume that the server is actually running on localhost:10000, probably bad for CI - expect_error(client <- Client$new(target="localhost:10000", client_options="bad"), - "'client_options' should be a Deephaven ClientOptions object. Got an object of type character instead.") - expect_error(client <- Client$new(target="localhost:10000", client_options=12345), - "'client_options' should be a Deephaven ClientOptions object. Got an object of type numeric instead.") - - # TODO: Invalid auth details needs better error handling from the R side - bad_client_options1 <- ClientOptions$new() - bad_client_options1$set_basic_authentication("my_username", "my_password") - expect_error(client <- Client$new(target="localhost:10000", client_options=bad_client_options1)) - - bad_client_options2 <- ClientOptions$new() - bad_client_options2$set_session_type("groovy") - expect_error(client <- Client$new(target="localhost:10000", client_options=bad_client_options2)) + # TODO: these all assume that the server is actually running on localhost:10000, probably bad for CI + expect_error( + client <- Client$new(target = "localhost:10000", client_options = "bad"), + "'client_options' should be a Deephaven ClientOptions object. Got an object of type character instead." + ) + expect_error( + client <- Client$new(target = "localhost:10000", client_options = 12345), + "'client_options' should be a Deephaven ClientOptions object. Got an object of type numeric instead." + ) + + # TODO: Invalid auth details needs better error handling from the R side + bad_client_options1 <- ClientOptions$new() + bad_client_options1$set_basic_authentication("my_username", "my_password") + expect_error(client <- Client$new(target = "localhost:10000", client_options = bad_client_options1)) + + bad_client_options2 <- ClientOptions$new() + bad_client_options2$set_session_type("groovy") + expect_error(client <- Client$new(target = "localhost:10000", client_options = bad_client_options2)) }) test_that("import_table fails nicely with bad inputs", { + library(datasets) - library(datasets) - - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) - - expect_error(client$import_table(12345), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class numeric instead.") - expect_error(client$import_table("hello!"), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class character instead.") - - # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. - data(iris) - expect_error(client$import_table(iris)) - - data(HairEyeColor) - expect_error(client$import_table(HairEyeColor), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class table instead.") + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) + + expect_error( + client$import_table(12345), + "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class numeric instead." + ) + expect_error( + client$import_table("hello!"), + "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class character instead." + ) + + # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. + data(iris) + expect_error(client$import_table(iris)) + + data(HairEyeColor) + expect_error( + client$import_table(HairEyeColor), + "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class table instead." + ) + + client$close() }) test_that("open_table fails nicely with bad inputs", { + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + expect_error(client$open_table(""), "The table '' you're trying to pull does not exist on the server.") + expect_error(client$open_table(12345), "'name' must be passed as a single string. Got an object of class numeric instead.") + expect_error(client$open_table(client_options), "'name' must be passed as a single string. Got an object of class ClientOptions instead.") + expect_error(client$open_table(c("I", "am", "string")), "'name' must be passed as a single string. Got a character vector of length 3 instead.") - expect_error(client$open_table(""), "The table '' you're trying to pull does not exist on the server.") - expect_error(client$open_table(12345), "'name' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client$open_table(client_options), "'name' must be passed as a single string. Got an object of class ClientOptions instead.") - expect_error(client$open_table(c("I", "am", "string")), "'name' must be passed as a single string. Got a character vector of length 3 instead.") + client$close() }) test_that("empty_table fails nicely with bad inputs", { + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + expect_error(client$empty_table(0), "'size' must be a positive integer. Got 0 instead.") + expect_error(client$empty_table(-3), "'size' must be a positive integer. Got -3 instead.") + expect_error(client$empty_table(1.2345), "'size' must be a positive integer. Got a non-integer numeric type instead.") + expect_error(client$empty_table("hello!"), "'size' must be a positive integer. Got an object of class character instead.") + expect_error(client$empty_table(c(1, 2, 3, 4)), "'size' must be a positive integer. Got a numeric vector of length 4 instead.") - expect_error(client$empty_table(0), "'size' must be a positive integer. Got 0 instead.") - expect_error(client$empty_table(-3), "'size' must be a positive integer. Got -3 instead.") - expect_error(client$empty_table(1.2345), "'size' must be a positive integer. Got a non-integer numeric type instead.") - expect_error(client$empty_table("hello!"), "'size' must be a positive integer. Got an object of class character instead.") - expect_error(client$empty_table(c(1, 2, 3, 4)), "'size' must be a positive integer. Got a numeric vector of length 4 instead.") + client$close() }) test_that("time_table fails nicely with bad inputs", { - - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) - - expect_error(client$time_table(1.23, 1000), "'start_time_nanos' must be an integer. Got a non-integer numeric type instead.") - expect_error(client$time_table(1000, 1.23), "'period_nanos' must be an integer. Got a non-integer numeric type instead.") - expect_error(client$time_table(c(1, 2, 3), 1000), "'start_time_nanos' must be an integer. Got a numeric vector of length 3 instead.") - expect_error(client$time_table(1000, c(1, 2, 3)), "'period_nanos' must be an integer. Got a numeric vector of length 3 instead.") - expect_error(client$time_table("hello!", 1000), "'start_time_nanos' must be an integer. Got an object of class character instead.") - expect_error(client$time_table(1000, "hello!"), "'period_nanos' must be an integer. Got an object of class character instead.") + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) + + expect_error(client$time_table(1.23, 1000), "'start_time_nanos' must be an integer. Got a non-integer numeric type instead.") + expect_error(client$time_table(1000, 1.23), "'period_nanos' must be an integer. Got a non-integer numeric type instead.") + expect_error(client$time_table(c(1, 2, 3), 1000), "'start_time_nanos' must be an integer. Got a numeric vector of length 3 instead.") + expect_error(client$time_table(1000, c(1, 2, 3)), "'period_nanos' must be an integer. Got a numeric vector of length 3 instead.") + expect_error(client$time_table("hello!", 1000), "'start_time_nanos' must be an integer. Got an object of class character instead.") + expect_error(client$time_table(1000, "hello!"), "'period_nanos' must be an integer. Got an object of class character instead.") + + client$close() }) test_that("run_script fails nicely with bad input types", { + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) + expect_error(client$run_script(12345), "'script' must be passed as a single string. Got an object of class numeric instead.") + expect_error(client$run_script(c("I", "am", "a", "string")), "'script' must be passed as a single string. Got a character vector of length 4 instead.") - expect_error(client$run_script(12345), "'script' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client$run_script(c("I", "am", "a", "string")), "'script' must be passed as a single string. Got a character vector of length 4 instead.") + client$close() }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index c1490a18730..50b9f569743 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -2,172 +2,204 @@ library(testthat) library(rdeephaven) setup <- function() { - - df1 <- data.frame(string_col = c("I", "am", "a", "string", "column"), - int_col = c(0, 1, 2, 3, 4), - dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00)) - - df2 <- data.frame(col1 = rep(3.14, 100), - col2 = rep("hello!", 100), - col3 = rnorm(100)) - - df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) - - df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[250000], - bool_col = sample(c(TRUE, FALSE), 250000, TRUE), - int_col = sample(0:10000, 250000, TRUE)) - - # in order to test TableHandle, we need to have tables on the server that we know everything about. - # thus, we have to push these created tables to the server and get TableHandles to each of them. - # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() - - # set up client - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) - - # move dataframes to server and get TableHandles for testing - th1 <- client$import_table(df1) - th2 <- client$import_table(df2) - th3 <- client$import_table(df3) - th4 <- client$import_table(df4) - - # time table to test is_static() - th5 <- client$time_table(0, 1000000000) %>% update("X = ii") - - return(list("client" = client, - "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5)) + df1 <- data.frame( + string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) + ) + + df2 <- data.frame( + col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100) + ) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame( + time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE) + ) + + # in order to test TableHandle, we need to have tables on the server that we know everything about. + # thus, we have to push these created tables to the server and get TableHandles to each of them. + # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() + + # set up client + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) + + # move dataframes to server and get TableHandles for testing + th1 <- client$import_table(df1) + th2 <- client$import_table(df2) + th3 <- client$import_table(df3) + th4 <- client$import_table(df4) + + # time table to test is_static() + th5 <- client$time_table(0, 1000000000) %>% update("X = ii") + + return(list( + "client" = client, + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5 + )) } ##### TESTING GOOD INPUTS ##### test_that("is_static returns the correct value", { - data <- setup() + data <- setup() + + expect_true(data$th1$is_static()) + expect_true(data$th2$is_static()) + expect_true(data$th3$is_static()) + expect_true(data$th4$is_static()) + expect_false(data$th5$is_static()) - expect_true(data$th1$is_static()) - expect_true(data$th2$is_static()) - expect_true(data$th3$is_static()) - expect_true(data$th4$is_static()) - expect_false(data$th5$is_static()) + data$client$close() }) test_that("nrow returns the correct number of rows", { - data <- setup() + data <- setup() - expect_equal(data$th1$nrow(), nrow(data$df1)) - expect_equal(data$th2$nrow(), nrow(data$df2)) - expect_equal(data$th3$nrow(), nrow(data$df3)) - expect_equal(data$th4$nrow(), nrow(data$df4)) + expect_equal(data$th1$nrow(), nrow(data$df1)) + expect_equal(data$th2$nrow(), nrow(data$df2)) + expect_equal(data$th3$nrow(), nrow(data$df3)) + expect_equal(data$th4$nrow(), nrow(data$df4)) + + data$client$close() }) test_that("bind_to_variable binds the table to a variable", { - data <- setup() + data <- setup() + + data$th1$bind_to_variable("table1") + expect_no_error(data$client$open_table("table1")) - data$th1$bind_to_variable("table1") - expect_no_error(data$client$open_table("table1")) + data$th2$bind_to_variable("table2") + expect_no_error(data$client$open_table("table2")) - data$th2$bind_to_variable("table2") - expect_no_error(data$client$open_table("table2")) + data$th3$bind_to_variable("table3") + expect_no_error(data$client$open_table("table3")) - data$th3$bind_to_variable("table3") - expect_no_error(data$client$open_table("table3")) + data$th4$bind_to_variable("table4") + expect_no_error(data$client$open_table("table4")) - data$th4$bind_to_variable("table4") - expect_no_error(data$client$open_table("table4")) + data$client$close() }) test_that("to_arrow_record_batch_stream_reader returns an identical stream reader", { - data <- setup() + data <- setup() - # actual equality of RecordBatchStreamReaders is not expected, as they contain underlying pointers to relevant data, - # as well as metadata from the Deephaven server, which we do not expect rbr created fully in R to have. - # We care about equality in the sense that coercing to dataframes should yield identical dataframes, so we cast to dataframes and compare. - # Additionally, as.data.frame() does not convert arrow tables to data frames, but to Tibbles. Need another as.data.frame to get a data frame. + # actual equality of RecordBatchStreamReaders is not expected, as they contain underlying pointers to relevant data, + # as well as metadata from the Deephaven server, which we do not expect rbr created fully in R to have. + # We care about equality in the sense that coercing to dataframes should yield identical dataframes, so we cast to dataframes and compare. + # Additionally, as.data.frame() does not convert arrow tables to data frames, but to Tibbles. Need another as.data.frame to get a data frame. - rbr1 <- data$th1$to_arrow_record_batch_stream_reader() - expect_equal(as.data.frame(as.data.frame(rbr1$read_table())), data$df1) - - rbr2 <- data$th2$to_arrow_record_batch_stream_reader() - expect_equal(as.data.frame(as.data.frame(rbr2$read_table())), data$df2) + rbr1 <- data$th1$to_arrow_record_batch_stream_reader() + expect_equal(as.data.frame(as.data.frame(rbr1$read_table())), data$df1) - rbr3 <- data$th3$to_arrow_record_batch_stream_reader() - expect_equal(as.data.frame(as.data.frame(rbr3$read_table())), data$df3) + rbr2 <- data$th2$to_arrow_record_batch_stream_reader() + expect_equal(as.data.frame(as.data.frame(rbr2$read_table())), data$df2) - rbr4 <- data$th4$to_arrow_record_batch_stream_reader() - expect_equal(as.data.frame(as.data.frame(rbr4$read_table())), data$df4) + rbr3 <- data$th3$to_arrow_record_batch_stream_reader() + expect_equal(as.data.frame(as.data.frame(rbr3$read_table())), data$df3) + + rbr4 <- data$th4$to_arrow_record_batch_stream_reader() + expect_equal(as.data.frame(as.data.frame(rbr4$read_table())), data$df4) + + data$client$close() }) test_that("to_arrow_table returns a valid Arrow table", { - data <- setup() + data <- setup() + + # The rationale for casting RecordBatchStreamReaders to dataframes for comparison also applies to Arrow Tables. + # Additionally, as.data.frame() does not convert arrow tables to data frames, but to Tibbles. Need another as.data.frame to get a data frame. - # The rationale for casting RecordBatchStreamReaders to dataframes for comparison also applies to Arrow Tables. - # Additionally, as.data.frame() does not convert arrow tables to data frames, but to Tibbles. Need another as.data.frame to get a data frame. + arrow_tbl1 <- data$th1$to_arrow_table() + expect_equal(as.data.frame(as.data.frame(arrow_tbl1)), data$df1) - arrow_tbl1 <- data$th1$to_arrow_table() - expect_equal(as.data.frame(as.data.frame(arrow_tbl1)), data$df1) - - arrow_tbl2 <- data$th2$to_arrow_table() - expect_equal(as.data.frame(as.data.frame(arrow_tbl2)), data$df2) + arrow_tbl2 <- data$th2$to_arrow_table() + expect_equal(as.data.frame(as.data.frame(arrow_tbl2)), data$df2) - arrow_tbl3 <- data$th3$to_arrow_table() - expect_equal(as.data.frame(as.data.frame(arrow_tbl3)), data$df3) + arrow_tbl3 <- data$th3$to_arrow_table() + expect_equal(as.data.frame(as.data.frame(arrow_tbl3)), data$df3) - arrow_tbl4 <- data$th4$to_arrow_table() - expect_equal(as.data.frame(as.data.frame(arrow_tbl4)), data$df4) + arrow_tbl4 <- data$th4$to_arrow_table() + expect_equal(as.data.frame(as.data.frame(arrow_tbl4)), data$df4) + + data$client$close() }) test_that("to_tibble returns a valid Tibble", { - data <- setup() + data <- setup() + + tibble1 <- data$th1$to_tibble() + expect_equal(tibble1, as_tibble(data$df1)) - tibble1 <- data$th1$to_tibble() - expect_equal(tibble1, as_tibble(data$df1)) - - tibble2 <- data$th2$to_tibble() - expect_equal(tibble2, as_tibble(data$df2)) + tibble2 <- data$th2$to_tibble() + expect_equal(tibble2, as_tibble(data$df2)) - tibble3 <- data$th3$to_tibble() - expect_equal(tibble3, as_tibble(data$df3)) + tibble3 <- data$th3$to_tibble() + expect_equal(tibble3, as_tibble(data$df3)) - tibble4 <- data$th4$to_tibble() - expect_equal(tibble4, as_tibble(data$df4)) + tibble4 <- data$th4$to_tibble() + expect_equal(tibble4, as_tibble(data$df4)) + + data$client$close() }) test_that("to_data_frame returns a valid data frame", { - data <- setup() + data <- setup() + + data_frame1 <- data$th1$to_data_frame() + expect_equal(data_frame1, data$df1) + + data_frame2 <- data$th2$to_data_frame() + expect_equal(data_frame2, data$df2) - data_frame1 <- data$th1$to_data_frame() - expect_equal(data_frame1, data$df1) - - data_frame2 <- data$th2$to_data_frame() - expect_equal(data_frame2, data$df2) + data_frame3 <- data$th3$to_data_frame() + expect_equal(data_frame3, data$df3) - data_frame3 <- data$th3$to_data_frame() - expect_equal(data_frame3, data$df3) + data_frame4 <- data$th4$to_data_frame() + expect_equal(data_frame4, data$df4) - data_frame4 <- data$th4$to_data_frame() - expect_equal(data_frame4, data$df4) + data$client$close() }) ##### TESTING BAD INPUTS ##### test_that("trying to instantiate a TableHandle directly fails nicely", { - - expect_error(TableHandle$new("hello!"), - "'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") + expect_error( + TableHandle$new("hello!"), + "'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised." + ) }) test_that("bind_to_variable fails nicely on bad inputs", { - data <- setup() + data <- setup() + + expect_error( + data$th1$bind_to_variable(12345), + "'name' must be passed as a single string. Got an object of class numeric instead." + ) - expect_error(data$th1$bind_to_variable(12345), - "'name' must be passed as a single string. Got an object of class numeric instead.") + expect_error( + data$th1$bind_to_variable(c("multiple", "strings")), + "'name' must be passed as a single string. Got a character vector of length 2 instead." + ) - expect_error(data$th1$bind_to_variable(c("multiple", "strings")), - "'name' must be passed as a single string. Got a character vector of length 2 instead.") + expect_error( + data$th1$bind_to_variable(data$df1), + "'name' must be passed as a single string. Got an object of class data.frame instead." + ) - expect_error(data$th1$bind_to_variable(data$df1), - "'name' must be passed as a single string. Got an object of class data.frame instead.") + expect_error( + data$th1$bind_to_variable(list("list", "of", "strings")), + "'name' must be passed as a single string. Got an object of class list instead." + ) - expect_error(data$th1$bind_to_variable(list("list", "of", "strings")), - "'name' must be passed as a single string. Got an object of class list instead.") + data$client$close() }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 36d3132cd2d..402633a3eeb 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -2,275 +2,300 @@ library(testthat) library(rdeephaven) setup <- function() { - - df1 <- data.frame(string_col = c("I", "am", "a", "string", "column"), - int_col = c(0, 1, 2, 3, 4), - dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00)) - - df2 <- data.frame(col1 = rep(3.14, 100), - col2 = rep("hello!", 100), - col3 = rnorm(100)) - - df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) - - df4 <- data.frame(time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date()+30), by = "1 sec")[250000], - bool_col = sample(c(TRUE, FALSE), 250000, TRUE), - int_col = sample(0:10000, 250000, TRUE)) - - df5 <- data.frame(X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), - Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), - Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), - Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214)) - - df6 <- data.frame(X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), - Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), - Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), - Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6)) - - # in order to test TableHandle, we need to have tables on the server that we know everything about. - # thus, we have to push these created tables to the server and get TableHandles to each of them. - # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() - - # set up client - client_options <- ClientOptions$new() - client <- Client$new(target="localhost:10000", client_options=client_options) - - # move dataframes to server and get TableHandles for testing - th1 <- client$import_table(df1) - th2 <- client$import_table(df2) - th3 <- client$import_table(df3) - th4 <- client$import_table(df4) - th5 <- client$import_table(df5) - th6 <- client$import_table(df6) - - return(list("client" = client, - "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6)) + df1 <- data.frame( + string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) + ) + + df2 <- data.frame( + col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100) + ) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame( + time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE) + ) + + df5 <- data.frame( + X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), + Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), + Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214) + ) + + df6 <- data.frame( + X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), + Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), + Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), + Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) + ) + + # in order to test TableHandle, we need to have tables on the server that we know everything about. + # thus, we have to push these created tables to the server and get TableHandles to each of them. + # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() + + # set up client + client_options <- ClientOptions$new() + client <- Client$new(target = "localhost:10000", client_options = client_options) + + # move dataframes to server and get TableHandles for testing + th1 <- client$import_table(df1) + th2 <- client$import_table(df2) + th3 <- client$import_table(df3) + th4 <- client$import_table(df4) + th5 <- client$import_table(df5) + th6 <- client$import_table(df6) + + return(list( + "client" = client, + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6 + )) } ##### TESTING GOOD INPUTS ##### test_that("select behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 %>% - dplyr::select(string_col) - new_th1 <- data$th1 %>% - select("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 %>% - dplyr::select(col2, col3) - new_th2 <- data$th2 %>% - select(c("col2", "col3")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 %>% - dplyr::select(X1, X2) %>% - rename(first_col = X1) - new_th3 <- data$th3 %>% - select(c("first_col = X1", "X2")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 %>% - dplyr::select(int_col) %>% - mutate(new_col = int_col + 1, .keep = "none") - new_th4 <- data$th4 %>% - select("new_col = int_col + 1") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 %>% - mutate(Number3 = Number1 * Number2) %>% - dplyr::select(X, Number3) - new_th5 <- data$th5 %>% - select(c("X", "Number3 = Number1 * Number2")) - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::select(string_col) + new_th1 <- data$th1 %>% + select("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::select(col2, col3) + new_th2 <- data$th2 %>% + select(c("col2", "col3")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::select(X1, X2) %>% + rename(first_col = X1) + new_th3 <- data$th3 %>% + select(c("first_col = X1", "X2")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::select(int_col) %>% + mutate(new_col = int_col + 1, .keep = "none") + new_th4 <- data$th4 %>% + select("new_col = int_col + 1") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 * Number2) %>% + dplyr::select(X, Number3) + new_th5 <- data$th5 %>% + select(c("X", "Number3 = Number1 * Number2")) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + data$client$close() }) test_that("view behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 %>% - dplyr::select(string_col) - new_th1 <- data$th1 %>% - view("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 %>% - dplyr::select(col2, col3) - new_th2 <- data$th2 %>% - view(c("col2", "col3")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 %>% - dplyr::select(X1, X2) %>% - rename(first_col = X1) - new_th3 <- data$th3 %>% - view(c("first_col = X1", "X2")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 %>% - dplyr::select(int_col) %>% - mutate(new_col = int_col + 1, .keep = "none") - new_th4 <- data$th4 %>% - view("new_col = int_col + 1") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 %>% - mutate(Number3 = Number1 * Number2) %>% - dplyr::select(X, Number3) - new_th5 <- data$th5 %>% - view(c("X", "Number3 = Number1 * Number2")) - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::select(string_col) + new_th1 <- data$th1 %>% + view("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::select(col2, col3) + new_th2 <- data$th2 %>% + view(c("col2", "col3")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + dplyr::select(X1, X2) %>% + rename(first_col = X1) + new_th3 <- data$th3 %>% + view(c("first_col = X1", "X2")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::select(int_col) %>% + mutate(new_col = int_col + 1, .keep = "none") + new_th4 <- data$th4 %>% + view("new_col = int_col + 1") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 * Number2) %>% + dplyr::select(X, Number3) + new_th5 <- data$th5 %>% + view(c("X", "Number3 = Number1 * Number2")) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + data$client$close() }) test_that("update behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 %>% - mutate(dbl_col_again = dbl_col) - new_th1 <- data$th1 %>% - update("dbl_col_again = dbl_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 %>% - mutate(col4 = col3 * 2) - new_th2 <- data$th2 %>% - update("col4 = col3 * 2") - expect_equal(as.data.frame(new_tb2), as.data.frame(new_th2)) - - new_tb3 <- data$df3 %>% - mutate(X1001 = X1000, X1002 = X1001) - new_th3 <- data$th3 %>% - update(c("X1001 = X1000", "X1002 = X1001")) - expect_equal(as.data.frame(new_tb3), as.data.frame(new_th3)) - - new_tb4 <- data$df4 %>% - mutate(new_col = sqrt(3 * int_col)) - new_th4 <- data$th4 %>% - update("new_col = sqrt(3 * int_col)") - expect_equal(as.data.frame(new_tb4), as.data.frame(new_th4)) - - new_tb5 <- data$df5 %>% - mutate(Number3 = Number1 + Number2) - new_th5 <- data$th5 %>% - update("Number3 = Number1 + Number2") - expect_equal(as.data.frame(new_tb5), as.data.frame(new_th5)) + data <- setup() + + new_tb1 <- data$df1 %>% + mutate(dbl_col_again = dbl_col) + new_th1 <- data$th1 %>% + update("dbl_col_again = dbl_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + mutate(col4 = col3 * 2) + new_th2 <- data$th2 %>% + update("col4 = col3 * 2") + expect_equal(as.data.frame(new_tb2), as.data.frame(new_th2)) + + new_tb3 <- data$df3 %>% + mutate(X1001 = X1000, X1002 = X1001) + new_th3 <- data$th3 %>% + update(c("X1001 = X1000", "X1002 = X1001")) + expect_equal(as.data.frame(new_tb3), as.data.frame(new_th3)) + + new_tb4 <- data$df4 %>% + mutate(new_col = sqrt(3 * int_col)) + new_th4 <- data$th4 %>% + update("new_col = sqrt(3 * int_col)") + expect_equal(as.data.frame(new_tb4), as.data.frame(new_th4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 + Number2) + new_th5 <- data$th5 %>% + update("Number3 = Number1 + Number2") + expect_equal(as.data.frame(new_tb5), as.data.frame(new_th5)) + + data$client$close() }) test_that("update_view behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 %>% - mutate(dbl_col_again = dbl_col) - new_th1 <- data$th1 %>% - update_view("dbl_col_again = dbl_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 %>% - mutate(col4 = col3 * 2) - new_th2 <- data$th2 %>% - update_view("col4 = col3 * 2") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 %>% - mutate(X1001 = X1000, X1002 = X1001) - new_th3 <- data$th3 %>% - update_view(c("X1001 = X1000", "X1002 = X1001")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 %>% - mutate(new_col = sqrt(3 * int_col)) - new_th4 <- data$th4 %>% - update_view("new_col = sqrt(3 * int_col)") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 %>% - mutate(Number3 = Number1 + Number2) - new_th5 <- data$th5 %>% - update_view("Number3 = Number1 + Number2") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + data <- setup() + + new_tb1 <- data$df1 %>% + mutate(dbl_col_again = dbl_col) + new_th1 <- data$th1 %>% + update_view("dbl_col_again = dbl_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + mutate(col4 = col3 * 2) + new_th2 <- data$th2 %>% + update_view("col4 = col3 * 2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + mutate(X1001 = X1000, X1002 = X1001) + new_th3 <- data$th3 %>% + update_view(c("X1001 = X1000", "X1002 = X1001")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + mutate(new_col = sqrt(3 * int_col)) + new_th4 <- data$th4 %>% + update_view("new_col = sqrt(3 * int_col)") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 %>% + mutate(Number3 = Number1 + Number2) + new_th5 <- data$th5 %>% + update_view("Number3 = Number1 + Number2") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + data$client$close() }) test_that("drop_columns behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% dplyr::select(-string_col) new_th1 <- data$th1 %>% drop_columns("string_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% dplyr::select(-c(col1, col2)) new_th2 <- data$th2 %>% drop_columns(c("col1", "col2")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% dplyr::select(-paste0("X", seq(2, 1000))) new_th3 <- data$th3 %>% drop_columns(paste0("X", seq(2, 1000))) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + data$client$close() }) test_that("where behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 %>% - filter(int_col < 3) - new_th1 <- data$th1 %>% - where("int_col < 3") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 %>% - filter(col2 == "hello!") - new_th2 <- data$th2 %>% - where("col2 == `hello!`") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 %>% - filter(X1 - X4 + X8 + X32 - 2*X5 >= 0) - new_th3 <- data$th3 %>% - where("X1 - X4 + X8 + X32 - 2*X5 >= 0") - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + data <- setup() + + new_tb1 <- data$df1 %>% + filter(int_col < 3) + new_th1 <- data$th1 %>% + where("int_col < 3") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + filter(col2 == "hello!") + new_th2 <- data$th2 %>% + where("col2 == `hello!`") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + filter(X1 - X4 + X8 + X32 - 2 * X5 >= 0) + new_th3 <- data$th3 %>% + where("X1 - X4 + X8 + X32 - 2*X5 >= 0") + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + data$client$close() }) test_that("group_by and ungroup behaves as expected", { - data <- setup() - - # There is not a clean analog to group_by() in dplyr, so we evaluate - # correctness by evaluating that these functions behave as inverses. - # Easiest when grouping columns are first, otherwise we must also reorder. - - new_th1 <- data$th1 %>% - group_by("string_col") %>% - ungroup() %>% - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(data$th1 %>% sort("string_col"))) - - new_th3 <- data$th3 %>% - group_by(c("X1", "X2", "X3", "X4", "X5")) %>% - ungroup() %>% - sort(c("X1", "X2", "X3", "X4", "X5")) - expect_equal(as.data.frame(new_th3), as.data.frame(data$th3 %>% sort(c("X1", "X2", "X3", "X4", "X5")))) - - new_th5 <- data$th5 %>% - group_by("X") %>% - ungroup() %>% - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(data$th5 %>% sort("X"))) - - new_th6 <- data$th6 %>% - group_by(c("X", "Y")) %>% - ungroup() %>% - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(data$th6 %>% sort(c("X", "Y")))) + data <- setup() + + # There is not a clean analog to group_by() in dplyr, so we evaluate + # correctness by evaluating that these functions behave as inverses. + # Easiest when grouping columns are first, otherwise we must also reorder. + + new_th1 <- data$th1 %>% + group_by("string_col") %>% + ungroup() %>% + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(data$th1 %>% sort("string_col"))) + + new_th3 <- data$th3 %>% + group_by(c("X1", "X2", "X3", "X4", "X5")) %>% + ungroup() %>% + sort(c("X1", "X2", "X3", "X4", "X5")) + expect_equal(as.data.frame(new_th3), as.data.frame(data$th3 %>% sort(c("X1", "X2", "X3", "X4", "X5")))) + + new_th5 <- data$th5 %>% + group_by("X") %>% + ungroup() %>% + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(data$th5 %>% sort("X"))) + + new_th6 <- data$th6 %>% + group_by(c("X", "Y")) %>% + ungroup() %>% + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(data$th6 %>% sort(c("X", "Y")))) + + data$client$close() }) test_that("first_by behaves as expected", { data <- setup() - + new_tb1 <- data$df5 %>% dplyr::select(-Y) %>% dplyr::group_by(X) %>% @@ -279,7 +304,7 @@ test_that("first_by behaves as expected", { drop_columns("Y") %>% first_by("X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df5 %>% dplyr::group_by(X, Y) %>% summarise(across(everything(), first)) %>% @@ -288,11 +313,13 @@ test_that("first_by behaves as expected", { first_by(c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("last_by behaves as expected", { data <- setup() - + new_tb1 <- data$df5 %>% dplyr::select(-Y) %>% dplyr::group_by(X) %>% @@ -301,7 +328,7 @@ test_that("last_by behaves as expected", { drop_columns("Y") %>% last_by("X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df5 %>% dplyr::group_by(X, Y) %>% summarise(across(everything(), last)) %>% @@ -310,171 +337,185 @@ test_that("last_by behaves as expected", { last_by(c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("head_by behaves as expected", { data <- setup() - + new_tb1 <- data$df5 %>% dplyr::group_by(X) %>% - slice_head(n=2) + slice_head(n = 2) new_th1 <- data$th5 %>% head_by(2, "X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df5 %>% dplyr::group_by(X, Y) %>% - slice_head(n=2) + slice_head(n = 2) new_th2 <- data$th5 %>% head_by(2, c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("tail_by behaves as expected", { data <- setup() - + new_tb1 <- data$df5 %>% dplyr::group_by(X) %>% - slice_tail(n=2) + slice_tail(n = 2) new_th1 <- data$th5 %>% tail_by(2, "X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df5 %>% dplyr::group_by(X, Y) %>% - slice_tail(n=2) + slice_tail(n = 2) new_th2 <- data$th5 %>% tail_by(2, c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("min_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 %>% - dplyr::group_by(int_col) %>% - summarise(across(everything(), min)) - new_th1 <- data$th1 %>% - min_by("int_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 %>% - dplyr::group_by(col2) %>% - summarise(across(everything(), min)) - new_th2 <- data$th2 %>% - min_by("col2") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 %>% - mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% - dplyr::group_by(bool_col1, bool_col2) %>% - summarise(across(everything(), min)) %>% - arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same - new_th3 <- data$th3 %>% - update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% - min_by(c("bool_col1", "bool_col2")) %>% - sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 %>% - dplyr::group_by(bool_col) %>% - summarise(across(everything(), min)) %>% - arrange(bool_col) - new_th4 <- data$th4 %>% - min_by("bool_col") %>% - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(int_col) %>% + summarise(across(everything(), min)) + new_th1 <- data$th1 %>% + min_by("int_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col2) %>% + summarise(across(everything(), min)) + new_th2 <- data$th2 %>% + min_by("col2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% + dplyr::group_by(bool_col1, bool_col2) %>% + summarise(across(everything(), min)) %>% + arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same + new_th3 <- data$th3 %>% + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% + min_by(c("bool_col1", "bool_col2")) %>% + sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(across(everything(), min)) %>% + arrange(bool_col) + new_th4 <- data$th4 %>% + min_by("bool_col") %>% + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + data$client$close() }) test_that("max_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 %>% - dplyr::group_by(int_col) %>% - summarise(across(everything(), max)) - new_th1 <- data$th1 %>% - max_by("int_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 %>% - dplyr::group_by(col2) %>% - summarise(across(everything(), max)) - new_th2 <- data$th2 %>% - max_by("col2") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 %>% - mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% - dplyr::group_by(bool_col1, bool_col2) %>% - summarise(across(everything(), max)) %>% - arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same - new_th3 <- data$th3 %>% - update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% - max_by(c("bool_col1", "bool_col2")) %>% - sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 %>% - dplyr::group_by(bool_col) %>% - summarise(across(everything(), max)) %>% - arrange(bool_col) - new_th4 <- data$th4 %>% - max_by("bool_col") %>% - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + data <- setup() + + new_tb1 <- data$df1 %>% + dplyr::group_by(int_col) %>% + summarise(across(everything(), max)) + new_th1 <- data$th1 %>% + max_by("int_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 %>% + dplyr::group_by(col2) %>% + summarise(across(everything(), max)) + new_th2 <- data$th2 %>% + max_by("col2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 %>% + mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) %>% + dplyr::group_by(bool_col1, bool_col2) %>% + summarise(across(everything(), max)) %>% + arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same + new_th3 <- data$th3 %>% + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) %>% + max_by(c("bool_col1", "bool_col2")) %>% + sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 %>% + dplyr::group_by(bool_col) %>% + summarise(across(everything(), max)) %>% + arrange(bool_col) + new_th4 <- data$th4 %>% + max_by("bool_col") %>% + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + data$client$close() }) test_that("sum_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - dplyr::select(-Y) %>% - dplyr::group_by(X) %>% - summarise(across(everything(), sum)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - sum_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - dplyr::group_by(X, Y) %>% - summarise(across(everything(), sum)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - sum_by(c("X", "Y")) %>% - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + data <- setup() + + new_tb1 <- data$df5 %>% + dplyr::select(-Y) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), sum)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + sum_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + dplyr::group_by(X, Y) %>% + summarise(across(everything(), sum)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + sum_by(c("X", "Y")) %>% + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("abs_sum_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - dplyr::select(-Y) %>% - mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% - dplyr::group_by(X) %>% - summarise(across(everything(), sum)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - abs_sum_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% - dplyr::group_by(X, Y) %>% - summarise(across(everything(), sum)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - abs_sum_by(c("X", "Y")) %>% - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + data <- setup() + + new_tb1 <- data$df5 %>% + dplyr::select(-Y) %>% + mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), sum)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + abs_sum_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + mutate(Number1 = abs(Number1), Number2 = abs(Number2)) %>% + dplyr::group_by(X, Y) %>% + summarise(across(everything(), sum)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + abs_sum_by(c("X", "Y")) %>% + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("avg_by behaves as expected", { data <- setup() - + new_tb1 <- data$df5 %>% dplyr::select(-Y) %>% dplyr::group_by(X) %>% @@ -483,7 +524,7 @@ test_that("avg_by behaves as expected", { drop_columns("Y") %>% avg_by("X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df5 %>% dplyr::group_by(X, Y) %>% summarise(across(everything(), mean)) %>% @@ -492,39 +533,47 @@ test_that("avg_by behaves as expected", { avg_by(c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("w_avg_by behaves as expected", { data <- setup() - + new_tb1 <- data$df5 %>% dplyr::select(-Y) %>% mutate(weights = Number1 * Number2) %>% dplyr::group_by(X) %>% - summarise(Number1 = weighted.mean(Number1, weights), - Number2 = weighted.mean(Number2, weights)) + summarise( + Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights) + ) new_th1 <- data$th5 %>% drop_columns("Y") %>% update("weights = Number1 * Number2") %>% w_avg_by("weights", "X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df5 %>% mutate(weights = Number1 * Number2) %>% dplyr::group_by(X, Y) %>% - summarise(Number1 = weighted.mean(Number1, weights), - Number2 = weighted.mean(Number2, weights)) %>% + summarise( + Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights) + ) %>% arrange(X, Y) new_th2 <- data$th5 %>% update("weights = Number1 * Number2") %>% w_avg_by("weights", c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("median_by behaves as expected", { data <- setup() - + new_tb1 <- data$df5 %>% dplyr::select(-Y) %>% dplyr::group_by(X) %>% @@ -533,7 +582,7 @@ test_that("median_by behaves as expected", { drop_columns("Y") %>% median_by("X") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df5 %>% dplyr::group_by(X, Y) %>% summarise(across(everything(), median)) %>% @@ -542,178 +591,210 @@ test_that("median_by behaves as expected", { median_by(c("X", "Y")) %>% sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("var_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - dplyr::select(-Y) %>% - dplyr::group_by(X) %>% - summarise(across(everything(), var)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - var_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - dplyr::group_by(X, Y) %>% - summarise(across(everything(), var)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - var_by(c("X", "Y")) %>% - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + data <- setup() + + new_tb1 <- data$df5 %>% + dplyr::select(-Y) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), var)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + var_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + dplyr::group_by(X, Y) %>% + summarise(across(everything(), var)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + var_by(c("X", "Y")) %>% + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("std_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - dplyr::select(-Y) %>% - dplyr::group_by(X) %>% - summarise(across(everything(), sd)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - std_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - dplyr::group_by(X, Y) %>% - summarise(across(everything(), sd)) %>% - arrange(X, Y) - new_th2 <- data$th5 %>% - std_by(c("X", "Y")) %>% - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + data <- setup() + + new_tb1 <- data$df5 %>% + dplyr::select(-Y) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), sd)) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + std_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + dplyr::group_by(X, Y) %>% + summarise(across(everything(), sd)) %>% + arrange(X, Y) + new_th2 <- data$th5 %>% + std_by(c("X", "Y")) %>% + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("percentile_by behaves as expected", { - data <- setup() - - # There is not a clean analog to `percentile_by` in dplyr, - # so we construct these data frames directly. - - new_df1 <- data.frame(X = c("A", "B", "C"), - Number1 = c(50, -44, -70), - Number2 = c(-50, 76, 130)) - new_th1 <- data$th5 %>% - drop_columns("Y") %>% - percentile_by(0.4, "X") - expect_equal(as.data.frame(new_th1), new_df1) - - new_df2 <- data.frame(X = c("A", "B", "A", "C", "B", "B", "C"), - Y = c("M", "N", "O", "N", "P", "O", "M"), - Number1 = c(50, -44, 49, 11, -66, 29, -70), - Number2 = c(-55, 76, 20, 130, 137, 73, 214)) - new_th2 <- data$th5 %>% - percentile_by(0.4, c("X", "Y")) - expect_equal(as.data.frame(new_th2), new_df2) + data <- setup() + + # There is not a clean analog to `percentile_by` in dplyr, + # so we construct these data frames directly. + new_df1 <- data.frame( + X = c("A", "B", "C"), + Number1 = c(50, -44, -70), + Number2 = c(-50, 76, 130) + ) + new_th1 <- data$th5 %>% + drop_columns("Y") %>% + percentile_by(0.4, "X") + expect_equal(as.data.frame(new_th1), new_df1) + + new_df2 <- data.frame( + X = c("A", "B", "A", "C", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "O", "M"), + Number1 = c(50, -44, 49, 11, -66, 29, -70), + Number2 = c(-55, 76, 20, 130, 137, 73, 214) + ) + new_th2 <- data$th5 %>% + percentile_by(0.4, c("X", "Y")) + expect_equal(as.data.frame(new_th2), new_df2) + + + data$client$close() }) test_that("count_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 %>% - count(X) - new_th1 <- data$th5 %>% - count_by("n", "X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 %>% - count(X, Y) - new_th2 <- data$th5 %>% - count_by("n", c("X", "Y")) %>% - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + data <- setup() + + new_tb1 <- data$df5 %>% + count(X) + new_th1 <- data$th5 %>% + count_by("n", "X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 %>% + count(X, Y) + new_th2 <- data$th5 %>% + count_by("n", c("X", "Y")) %>% + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + data$client$close() }) test_that("sort behaves as expected", { data <- setup() - + new_tb1 <- data$df1 %>% arrange(dbl_col) new_th1 <- data$th1 %>% sort("dbl_col") expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - + new_tb2 <- data$df2 %>% arrange(desc(col3)) new_th2 <- data$th2 %>% sort("col3", descending = TRUE) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - + new_tb3 <- data$df3 %>% arrange(X1, X2, X3, X4, X5) new_th3 <- data$th3 %>% sort(c("X1", "X2", "X3", "X4", "X5")) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - + new_tb4 <- data$df4 %>% arrange(desc(bool_col), desc(int_col)) new_th4 <- data$th4 %>% sort(c("bool_col", "int_col"), descending = TRUE) expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - + new_tb5 <- data$df5 %>% arrange(X, desc(Y), Number1) new_th5 <- data$th5 %>% sort(c("X", "Y", "Number1"), descending = c(FALSE, TRUE, FALSE)) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + data$client$close() }) test_that("cross_join behaves as expected", { - data <- setup() - - new_th1 <- data$th5 %>% - cross_join(data$th6, columns_to_match = character(), - columns_to_add = c("X_y = X", "Y_y = Y", "Number1_y = Number1", "Number2_y = Number2")) - new_tb1 <- data$df5 %>% - dplyr::cross_join(data$df6) %>% - rename(X = X.x, Y = Y.x, Number1 = Number1.x, Number2 = Number2.x, - X_y = X.y, Y_y = Y.y, Number1_y = Number1.y, Number2_y = Number2.y) - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + data <- setup() + + new_th1 <- data$th5 %>% + cross_join(data$th6, + columns_to_match = character(), + columns_to_add = c("X_y = X", "Y_y = Y", "Number1_y = Number1", "Number2_y = Number2") + ) + new_tb1 <- data$df5 %>% + dplyr::cross_join(data$df6) %>% + rename( + X = X.x, Y = Y.x, Number1 = Number1.x, Number2 = Number2.x, + X_y = X.y, Y_y = Y.y, Number1_y = Number1.y, Number2_y = Number2.y + ) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + data$client$close() }) test_that("natural_join behaves as expected", { - data <- setup() - - new_th2 <- data$th6 %>% - drop_columns("Y") %>% - avg_by("X") - new_th1 <- data$th5 %>% - natural_join(new_th2, columns_to_match = "X", - columns_to_add = c("Number3 = Number1", "Number4 = Number2")) - - new_tb2 <- data$df6 %>% - dplyr::select(-Y) %>% - dplyr::group_by(X) %>% - summarise(across(everything(), mean)) - new_tb1 <- data$df5 %>% - left_join(new_tb2, by = "X") %>% - rename(Number1 = Number1.x, Number2 = Number2.x, - Number3 = Number1.y, Number4 = Number2.y) - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + data <- setup() + + new_th2 <- data$th6 %>% + drop_columns("Y") %>% + avg_by("X") + new_th1 <- data$th5 %>% + natural_join(new_th2, + columns_to_match = "X", + columns_to_add = c("Number3 = Number1", "Number4 = Number2") + ) + + new_tb2 <- data$df6 %>% + dplyr::select(-Y) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), mean)) + new_tb1 <- data$df5 %>% + left_join(new_tb2, by = "X") %>% + rename( + Number1 = Number1.x, Number2 = Number2.x, + Number3 = Number1.y, Number4 = Number2.y + ) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + data$client$close() }) # TODO: Verify that inner_join is the analog of exact_join test_that("exact_join behaves as expected", { - data <- setup() - - new_th2 <- data$th6 %>% - drop_columns("Y") %>% - avg_by("X") - new_th1 <- data$th5 %>% - exact_join(new_th2, columns_to_match = "X", - columns_to_add = c("Number3 = Number1", "Number4 = Number2")) - - new_tb2 <- data$df6 %>% - dplyr::select(-Y) %>% - dplyr::group_by(X) %>% - summarise(across(everything(), mean)) - new_tb1 <- data$df5 %>% - inner_join(new_tb2, by = "X") %>% - rename(Number1 = Number1.x, Number2 = Number2.x, Number3 = Number1.y, Number4 = Number2.y) - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + data <- setup() + + new_th2 <- data$th6 %>% + drop_columns("Y") %>% + avg_by("X") + new_th1 <- data$th5 %>% + exact_join(new_th2, + columns_to_match = "X", + columns_to_add = c("Number3 = Number1", "Number4 = Number2") + ) + + new_tb2 <- data$df6 %>% + dplyr::select(-Y) %>% + dplyr::group_by(X) %>% + summarise(across(everything(), mean)) + new_tb1 <- data$df5 %>% + inner_join(new_tb2, by = "X") %>% + rename(Number1 = Number1.x, Number2 = Number2.x, Number3 = Number1.y, Number4 = Number2.y) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + data$client$close() }) From f7810061af64a7f1954cbf8dbe70d97d1cd9cc24 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 31 Jul 2023 10:09:28 -0500 Subject: [PATCH 36/73] Fix rbind implementation --- R/rdeephaven/R/helper_functions.R | 4 ++++ R/rdeephaven/R/table_handle_wrapper.R | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 1ee77266071..0000afadfda 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -70,3 +70,7 @@ verify_string_vector <- function(arg_name, string_vector_candidate) { strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { return(r6_aggregation$internal_aggregation) } + +strip_r6_wrapping_from_table_handle <- function(r6_table_handle) { + return(r6_table_handle$internal_table_handle) +} diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 737f1f85990..4d9a23aac58 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -142,5 +142,8 @@ tail.TableHandle <- function(th, n) { #' @export rbind.TableHandle <- function(th, sources) { - return(TableHandle$new(th$internal_table_handle$merge(sources))) + verify_internal_type("TableHandle", "sources", sources) + sources <- c(sources) + unwrapped_sources <- lapply(sources, strip_r6_wrapping_from_table_handle) + return(TableHandle$new(th$internal_table_handle$merge(unwrapped_sources))) } From 008ac446d3d40a8f288f0f3336d8c5f8b7a49c7e Mon Sep 17 00:00:00 2001 From: Alex Peters <80283343+alexpeters1208@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:07:05 -0500 Subject: [PATCH 37/73] Update DESCRIPTION w/ version --- R/rdeephaven/DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/rdeephaven/DESCRIPTION b/R/rdeephaven/DESCRIPTION index cadc81db8a5..079df08c5ed 100644 --- a/R/rdeephaven/DESCRIPTION +++ b/R/rdeephaven/DESCRIPTION @@ -1,7 +1,7 @@ Package: rdeephaven Type: Package Title: R Client for Deephaven Core -Version: 1.0 +Version: 0.26.0 Date: 2023-05-12 Author: Deephaven Data Labs Maintainer: Alex Peters From 19008f42c8424e9139783768cf95f6bfaa273160 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 31 Jul 2023 17:54:23 -0500 Subject: [PATCH 38/73] Fix problems from merge conflict --- R/rdeephaven/R/table_handle_wrapper.R | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index f257817e7b5..4d9a23aac58 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -38,12 +38,6 @@ TableHandle <- R6Class("TableHandle", private$is_static_field <- self$internal_table_handle$is_static() }, - #' @description - #' Whether the table referenced by this TableHandle is static or not. - #' @return TRUE if the table is static, or FALSE if the table is ticking. - is_static = function() { - return(private$is_static_field) - }, #' @description #' Whether the table referenced by this TableHandle is static or not. #' @return TRUE if the table is static, or FALSE if the table is ticking. @@ -79,14 +73,6 @@ TableHandle <- R6Class("TableHandle", return(rbsr) }, - #' @description - #' Imports the table referenced by this TableHandle into an Arrow Table. - #' @return A Table containing the data from the table referenced by this TableHandle. - to_arrow_table = function() { - rbsr <- self$to_arrow_record_batch_stream_reader() - arrow_tbl <- rbsr$read_table() - return(arrow_tbl) - }, #' @description #' Imports the table referenced by this TableHandle into an Arrow Table. #' @return A Table containing the data from the table referenced by this TableHandle. @@ -96,14 +82,6 @@ TableHandle <- R6Class("TableHandle", return(arrow_tbl) }, - #' @description - #' Imports the table referenced by this TableHandle into a dplyr Tibble. - #' @return A Tibble containing the data from the table referenced by this TableHandle. - to_tibble = function() { - rbsr <- self$to_arrow_record_batch_stream_reader() - arrow_tbl <- rbsr$read_table() - return(as_tibble(arrow_tbl)) - }, #' @description #' Imports the table referenced by this TableHandle into a dplyr Tibble. #' @return A Tibble containing the data from the table referenced by this TableHandle. From d29e6bbb02397409cb441bd23d01b7fbb66837c0 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 2 Aug 2023 13:43:38 -0500 Subject: [PATCH 39/73] Refactor helper functions --- R/rdeephaven/R/aggregate_wrapper.R | 30 ++--- R/rdeephaven/R/client_options_wrapper.R | 26 ++-- R/rdeephaven/R/client_wrapper.R | 14 +- R/rdeephaven/R/helper_functions.R | 122 ++++++++++-------- R/rdeephaven/R/table_handle_wrapper.R | 8 +- R/rdeephaven/R/table_ops.R | 76 +++++------ .../tests/testthat/test_aggregate_wrapper.R | 10 +- .../testthat/test_client_options_wrapper.R | 26 ++-- .../inst/tests/testthat/test_client_wrapper.R | 6 +- .../testthat/test_table_handle_wrapper.R | 6 +- 10 files changed, 172 insertions(+), 152 deletions(-) diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R index 234f1695f76..3219f65befe 100644 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -19,80 +19,80 @@ Aggregation <- R6Class("Aggregation", #' @export agg_first <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_first(columns))) } #' @export agg_last <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_last(columns))) } #' @export agg_min <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_min(columns))) } #' @export agg_max <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_max(columns))) } #' @export agg_sum <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_sum(columns))) } #' @export agg_abs_sum <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_abs_sum(columns))) } #' @export agg_avg <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_avg(columns))) } #' @export agg_w_avg <- function(weight_column, columns = character()) { - verify_string("weight_column", weight_column) - verify_string_vector("columns", columns) + verify_string("weight_column", weight_column, TRUE) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) } #' @export agg_median <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_median(columns))) } #' @export agg_var <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_var(columns))) } #' @export agg_std <- function(columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_std(columns))) } #' @export agg_percentile <- function(percentile, columns = character()) { - verify_proportion("percentile", percentile) - verify_string_vector("columns", columns) + verify_in_unit_interval("percentile", percentile, TRUE) + verify_string("columns", columns, FALSE) return(Aggregation$new(INTERNAL_percentile(percentile, columns))) } #' @export agg_count <- function(count_column) { - verify_string("count_column", count_column) + verify_string("count_column", count_column, TRUE) return(Aggregation$new(INTERNAL_count(count_column))) } diff --git a/R/rdeephaven/R/client_options_wrapper.R b/R/rdeephaven/R/client_options_wrapper.R index bc65fbea631..93e164377be 100644 --- a/R/rdeephaven/R/client_options_wrapper.R +++ b/R/rdeephaven/R/client_options_wrapper.R @@ -54,8 +54,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param username Username of the account to use for authentication, supplied as a string. #' @param password Password of the account, supplied as a string. set_basic_authentication = function(username, password) { - verify_string("username", username) - verify_string("password", password) + verify_string("username", username, TRUE) + verify_string("password", password, TRUE) self$internal_client_options$set_basic_authentication(username, password) }, @@ -64,8 +64,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param auth_key Key to use for authentication, supplied as a string. #' @param auth_value Value to use for authentication, supplied as a string. set_custom_authentication = function(auth_key, auth_value) { - verify_string("auth_key", auth_key) - verify_string("auth_value", auth_value) + verify_string("auth_key", auth_key, TRUE) + verify_string("auth_value", auth_value, TRUE) self$internal_client_options$set_custom_authentication(auth_key, auth_value) }, @@ -73,7 +73,7 @@ ClientOptions <- R6Class("ClientOptions", #' Set the session type of the console (e.g., "python", "groovy", etc.). The session type must be supported on the server. #' @param session_type Desired language of the console. "python", "groovy", etc. set_session_type = function(session_type) { - verify_string("session_type", session_type) + verify_string("session_type", session_type, TRUE) self$internal_client_options$set_session_type(session_type) }, @@ -81,7 +81,7 @@ ClientOptions <- R6Class("ClientOptions", #' Use the TLS protocol in authentication and subsequent communication. #' @param root_certs Optional PEM-encoded certificate root for server connections. Defaults to system defaults. use_tls = function(root_certs = "") { - verify_string("root_certs", root_certs) + verify_string("root_certs", root_certs, TRUE) self$internal_client_options$set_use_tls(TRUE) self$internal_client_options$set_tls_root_certs(root_certs) }, @@ -89,10 +89,10 @@ ClientOptions <- R6Class("ClientOptions", #' Adds an int-valued option for the configuration of the underlying gRPC channels. #' @param opt The option key. - #' @param val The option value. + #' @param val The option value, assumed to be a scalar integer. add_int_option = function(opt, val) { - verify_string("opt", opt) - verify_int("val", val) + verify_string("opt", opt, TRUE) + verify_any_int("val", val, TRUE) self$internal_client_options$add_int_option(opt, val) }, @@ -101,8 +101,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param opt The option key. #' @param val The option valiue. add_string_option = function(opt, val) { - verify_string("opt", opt) - verify_string("val", val) + verify_string("opt", opt, TRUE) + verify_string("val", val, TRUE) self$internal_client_options$add_string_option(opt, val) }, @@ -111,8 +111,8 @@ ClientOptions <- R6Class("ClientOptions", #' @param header_name The header name #' @param header_value The header value add_extra_header = function(header_name, header_value) { - verify_string("header_name", header_name) - verify_string("header_value", header_value) + verify_string("header_name", header_name, TRUE) + verify_string("header_value", header_value, TRUE) self$internal_client_options$add_extra_header(header_name, header_value) }, internal_client_options = NULL diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 1f48bff5666..3f9d78e9178 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -33,7 +33,7 @@ Client <- R6Class("Client", #' @param client_options ClientOptions instance with the parameters needed to connect to the server. #' See ?ClientOptions for more information. initialize = function(target, client_options) { - verify_string("target", target) + verify_string("target", target, TRUE) if (first_class(client_options) != "ClientOptions") { stop(paste("'client_options' should be a Deephaven ClientOptions object. Got an object of type", first_class(client_options), "instead.")) } @@ -48,7 +48,7 @@ Client <- R6Class("Client", #' @param name Name of the table to open from the server, passed as a string. #' @return TableHandle reference to the requested table. open_table = function(name) { - verify_string("name", name) + verify_string("name", name, TRUE) if (!private$check_for_table(name)) { stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) } @@ -61,7 +61,7 @@ Client <- R6Class("Client", #' @return TableHandle reference to the new table, which has not yet been named on the server. #' See TableHandle$bind_to_variable() for naming a new table on the server. empty_table = function(size) { - verify_int("size", size, type = "positive") + verify_positive_int("size", size, TRUE) return(TableHandle$new(private$internal_client$empty_table(size))) }, @@ -71,9 +71,9 @@ Client <- R6Class("Client", #' @param period_nanos Table ticking frequency (in nanoseconds). #' @return TableHandle reference to the new table, which has not yet been named on the server. #' See TableHandle$bind_to_variable() for naming a new table on the server. - time_table = function(start_time_nanos, period_nanos) { - verify_int("start_time_nanos", start_time_nanos) - verify_int("period_nanos", period_nanos) + time_table = function(period_nanos, start_time_nanos = 0) { + verify_any_int("period_nanos", period_nanos, TRUE) + verify_any_int("start_time_nanos", start_time_nanos, TRUE) return(TableHandle$new(private$internal_client$time_table(start_time_nanos, period_nanos))) }, @@ -105,7 +105,7 @@ Client <- R6Class("Client", #' Runs a script on the server. The script must be in the language that the server console was started with. #' @param script Code to be executed on the server, passed as a string. run_script = function(script) { - verify_string("script", script) + verify_string("script", script, TRUE) private$internal_client$run_script(script) }, diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 0000afadfda..25cd16f0923 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -1,70 +1,90 @@ -first_class <- function(arg) class(arg)[[1]] +first_class <- function(arg) { return(class(arg)[[1]]) } -verify_internal_type <- function(desired_type, arg_name, candidate) { - if ((first_class(candidate) == "list") && (any(lapply(candidate, first_class) != desired_type))) { - stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got a vector with at least one element that is not a Deephaven ", desired_type, " instead.")) - } else if ((first_class(candidate) != "list") && (first_class(candidate) != desired_type)) { - stop(paste0("'", arg_name, "' must be a Deephaven ", desired_type, ", or a vector of ", desired_type, "s. Got an object of class ", first_class(candidate), " instead.")) +verify_type <- function(arg_name, candidate, required_type, message_type_name, is_scalar) { + if(first_class(candidate) == "list") { + if(any(lapply(candidate, first_class) != required_type)) { + stop(paste0("'", arg_name, "' must be a ", message_type_name, ", or a vector of ", message_type_name, "s. Got a vector with at least one element that is not a ", message_type_name, " instead.")) + } + } + else { + if(first_class(candidate) != required_type) { + if(is_scalar) { + stop(paste0("'", arg_name, "' must be passed as a single ", message_type_name, ". Got an object of class ", first_class(candidate), " instead.")) + } + else { + stop(paste0("'", arg_name, "' must be passed as a ", message_type_name, " or a vector of ", message_type_name, "s. Got an object of class ", first_class(candidate), " instead.")) + } + } + } + if(is_scalar) { + if(length(candidate) != 1) { + stop(paste0("'", arg_name, "' must be passed as a single ", message_type_name, ". Got a ", message_type_name, " vector of length ", length(candidate), " instead.")) + } } } -verify_bool <- function(arg_name, bool_candidate) { - if (first_class(bool_candidate) != "logical") { - stop(paste0("'", arg_name, "' must be passed as a single boolean. Got an object of class ", first_class(bool_candidate), " instead.")) - } else if (length(bool_candidate) != 1) { - stop(paste0("'", arg_name, "' must be passed as a single boolean. Got a boolean vector of length ", length(bool_candidate), " instead.")) +# does not attempt to verify that candidate is numeric +verify_in_range <- function(arg_name, candidate, a = NULL, b = NULL, a_open = TRUE, b_open = TRUE) { + + printed_interval = paste0(ifelse(a_open, "(", "["), ifelse(is.null(a), "-inf", as.character(a)), + ", ", ifelse(is.null(b), "inf", as.character(b)), ifelse(b_open, ")", "]")) + + if(((!is.null(a)) && ((any(candidate <= a) && (a_open)) || (any(candidate < a) && (!a_open)))) || + ((!is.null(b)) && ((any(candidate >= b) && (b_open)) || (any(candidate > b) && (!b_open))))) { + + if(length(candidate) == 1) { + stop(paste0("'", arg_name, "' must be in the interval ", printed_interval, ". Got '", arg_name, "' = ", candidate, " instead.")) + } + else { + stop(paste0("Every element of '", arg_name, "' must be in the interval ", printed_interval, ". Got at least one element outside of this interval instead.")) + } } } -verify_bool_vector <- function(arg_name, bool_candidate) { - if (first_class(bool_candidate) != "logical") { - stop(paste0("'", arg_name, "' must be passed as a boolean or a vector of booleans. Got an object of class ", first_class(bool_candidate), " instead.")) +# does not attempt to verify that candidate is numeric +verify_int <- function(arg_name, candidate) { + if(candidate != as.integer(candidate)) { + if(length(candidate == 1)) { + stop(paste0("'", arg_name, "' must be an integer. Got '", arg_name, "' = ", candidate, " instead.")) + } + else { + stop(paste0("Every element of '", arg_name, "' must be an integer. Got at least one non-integer element instead.")) + } } } -verify_int <- function(arg_name, int_candidate, type = "any") { - if (type == "any") { - message <- " an " - } else if (type == "nonnegative") { - message <- " a non-negative " - } else if (type == "positive") { - message <- " a positive " - } - if (class(int_candidate)[[1]] != "numeric") { - stop(paste0("'", arg_name, "' must be", message, "integer. Got an object of class ", first_class(int_candidate), " instead.")) - } else if (all.equal(int_candidate, as.integer(int_candidate)) != TRUE) { - # must use != TRUE as the result of all.equal() is not strictly boolean - stop(paste0("'", arg_name, "' must be", message, "integer. Got a non-integer numeric type instead.")) - } else if (length(int_candidate) != 1) { - stop(paste0("'", arg_name, "' must be", message, "integer. Got a numeric vector of length ", length(int_candidate), " instead.")) - } - if (((type == "nonnegative") && (int_candidate < 0)) || ((type == "positive") && (int_candidate <= 0))) { - stop(paste0("'", arg_name, "' must be", message, "integer. Got ", int_candidate, " instead.")) - } +verify_string <- function(arg_name, candidate, is_scalar) { + verify_type(arg_name, candidate, "character", "string", is_scalar) } -verify_proportion <- function(arg_name, prop_candidate) { - if (first_class(prop_candidate) != "numeric") { - stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got an object of class ", first_class(prop_candidate), " instead.")) - } else if (length(prop_candidate) != 1) { - stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length ", length(prop_candidate), " instead.")) - } else if ((prop_candidate < 0.0) || (prop_candidate > 1.0)) { - stop(paste0("'", arg_name, "' must be a numeric type between 0 and 1 inclusive. Got a value of ", prop_candidate, " instead.")) - } +verify_bool <- function(arg_name, candidate, is_scalar) { + verify_type(arg_name, candidate, "logical", "boolean", is_scalar) } -verify_string <- function(arg_name, string_candidate) { - if (first_class(string_candidate) != "character") { - stop(paste0("'", arg_name, "' must be passed as a single string. Got an object of class ", first_class(string_candidate), " instead.")) - } else if (length(string_candidate) != 1) { - stop(paste0("'", arg_name, "' must be passed as a single string. Got a character vector of length ", length(string_candidate), " instead.")) - } +verify_numeric <- function(arg_name, candidate, is_scalar) { + verify_type(arg_name, candidate, "numeric", "numeric", is_scalar) } -verify_string_vector <- function(arg_name, string_vector_candidate) { - if (first_class(string_vector_candidate) != "character") { - stop(paste0("'", arg_name, "' must be passed as a string or a vector of strings. Got an object of class ", first_class(string_vector_candidate), " instead.")) - } +verify_in_unit_interval <- function(arg_name, candidate, is_scalar) { + verify_numeric(arg_name, candidate, is_scalar) + verify_in_range(arg_name, candidate, a = 0, b = 1, a_open = FALSE, b_open = FALSE) +} + +verify_any_int <- function(arg_name, candidate, is_scalar) { + verify_numeric(arg_name, candidate, is_scalar) + verify_int(arg_name, candidate) +} + +verify_nonnegative_int <- function(arg_name, candidate, is_scalar) { + verify_numeric(arg_name, candidate, is_scalar) + verify_int(arg_name, candidate) + verify_in_range(arg_name, candidate, a = 0, a_open = FALSE) +} + +verify_positive_int <- function(arg_name, candidate, is_scalar) { + verify_numeric(arg_name, candidate, is_scalar) + verify_int(arg_name, candidate) + verify_in_range(arg_name, candidate, a = 0) } strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 4d9a23aac58..e99a645dc7c 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -60,7 +60,7 @@ TableHandle <- R6Class("TableHandle", #' enabling it to be accessed by that name from any Deephaven API. #' @param name Name for this table on the server. bind_to_variable = function(name) { - verify_string("name", name) + verify_string("name", name, TRUE) self$internal_table_handle$bind_to_variable(name) }, @@ -130,19 +130,19 @@ as.data.frame.TableHandle <- function(th, ...) { #' @export head.TableHandle <- function(th, n) { - verify_int("n", n) + verify_positive_int("n", n, TRUE) return(TableHandle$new(th$internal_table_handle$head(n))) } #' @export tail.TableHandle <- function(th, n) { - verify_int("n", n) + verify_positive_int("n", n, TRUE) return(TableHandle$new(th$internal_table_handle$tail(n))) } #' @export rbind.TableHandle <- function(th, sources) { - verify_internal_type("TableHandle", "sources", sources) + verify_type("sources", sources, "TableHandle", "Deephaven TableHandle", FALSE) sources <- c(sources) unwrapped_sources <- lapply(sources, strip_r6_wrapping_from_table_handle) return(TableHandle$new(th$internal_table_handle$merge(unwrapped_sources))) diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 55386094e02..d16d926a414 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -14,7 +14,7 @@ NULL #' @param by A string or list of strings specifying the columns to view. #' @export select <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) TableHandle$new(th$internal_table_handle$select(columns)) } @@ -24,7 +24,7 @@ select <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export view <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$view(columns))) } @@ -34,7 +34,7 @@ view <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export update <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$update(columns))) } @@ -44,7 +44,7 @@ update <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export update_view <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$update_view(columns))) } @@ -54,7 +54,7 @@ update_view <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export drop_columns <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$drop_columns(columns))) } @@ -64,7 +64,7 @@ drop_columns <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export where <- function(th, condition) { - verify_string("condition", condition) + verify_string("condition", condition, TRUE) return(TableHandle$new(th$internal_table_handle$where(condition))) } @@ -76,7 +76,7 @@ where <- function(th, condition) { #' @return TableHandle reference to the new table. #' @export group_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$group_by(columns))) } @@ -87,7 +87,7 @@ group_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export ungroup <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$ungroup(columns))) } @@ -99,8 +99,8 @@ ungroup <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export agg_by <- function(th, aggregations, columns = character()) { - verify_internal_type("Aggregation", "aggregations", aggregations) - verify_string_vector("columns", columns) + verify_type("aggregations", aggregations, "Aggregation", "Deephaven Aggregation", FALSE) + verify_string("columns", columns, FALSE) aggregations <- c(aggregations) unwrapped_aggregations <- lapply(aggregations, strip_r6_wrapping_from_aggregation) return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, columns))) @@ -112,7 +112,7 @@ agg_by <- function(th, aggregations, columns = character()) { #' @return TableHandle reference to the new table. #' @export first_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$first_by(columns))) } @@ -122,7 +122,7 @@ first_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export last_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$last_by(columns))) } @@ -133,8 +133,8 @@ last_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export head_by <- function(th, n, columns = character()) { - verify_int("n", n) - verify_string_vector("columns", columns) + verify_positive_int("n", n, TRUE) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) } @@ -145,8 +145,8 @@ head_by <- function(th, n, columns = character()) { #' @return TableHandle reference to the new table. #' @export tail_by <- function(th, n, columns = character()) { - verify_int("n", n) - verify_string_vector("columns", columns) + verify_positive_int("n", n, TRUE) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) } @@ -156,7 +156,7 @@ tail_by <- function(th, n, columns = character()) { #' @return TableHandle reference to the new table. #' @export min_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$min_by(columns))) } @@ -166,7 +166,7 @@ min_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export max_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$max_by(columns))) } @@ -176,7 +176,7 @@ max_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export sum_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$sum_by(columns))) } @@ -186,7 +186,7 @@ sum_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export abs_sum_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) } @@ -196,7 +196,7 @@ abs_sum_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export avg_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$avg_by(columns))) } @@ -207,8 +207,8 @@ avg_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export w_avg_by <- function(th, weight_column, columns = character()) { - verify_string("weight_column", weight_column) - verify_string_vector("columns", columns) + verify_string("weight_column", weight_column, TRUE) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) } @@ -218,7 +218,7 @@ w_avg_by <- function(th, weight_column, columns = character()) { #' @return TableHandle reference to the new table. #' @export median_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$median_by(columns))) } @@ -228,7 +228,7 @@ median_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export var_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$var_by(columns))) } @@ -238,7 +238,7 @@ var_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export std_by <- function(th, columns = character()) { - verify_string_vector("columns", columns) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$std_by(columns))) } @@ -250,8 +250,8 @@ std_by <- function(th, columns = character()) { #' @return TableHandle reference to the new table. #' @export percentile_by <- function(th, percentile, columns = character()) { - verify_proportion("percentile", percentile) - verify_string_vector("columns", columns) + verify_in_unit_interval("percentile", percentile, TRUE) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$percentile_by(percentile, columns))) } @@ -262,8 +262,8 @@ percentile_by <- function(th, percentile, columns = character()) { #' @return TableHandle reference to the new table. #' @export count_by <- function(th, count_by_column = "n", columns = character()) { - verify_string("count_by_column", count_by_column) - verify_string_vector("columns", columns) + verify_string("count_by_column", count_by_column, TRUE) + verify_string("columns", columns, FALSE) return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) } @@ -272,8 +272,8 @@ count_by <- function(th, count_by_column = "n", columns = character()) { # TODO: Figure out the right defaults here to make interpretation simple #' @export cross_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) + verify_string("columns_to_match", columns_to_match, FALSE) + verify_string("columns_to_add", columns_to_add, FALSE) return(TableHandle$new(th$internal_table_handle$cross_join( right_side$internal_table_handle, columns_to_match, columns_to_add @@ -283,8 +283,8 @@ cross_join <- function(th, right_side, columns_to_match, columns_to_add) { # TODO: Document this well #' @export natural_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) + verify_string("columns_to_match", columns_to_match, FALSE) + verify_string("columns_to_add", columns_to_add, FALSE) return(TableHandle$new(th$internal_table_handle$natural_join( right_side$internal_table_handle, columns_to_match, columns_to_add @@ -294,8 +294,8 @@ natural_join <- function(th, right_side, columns_to_match, columns_to_add) { # TODO: Document this well #' @export exact_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string_vector("columns_to_match", columns_to_match) - verify_string_vector("columns_to_add", columns_to_add) + verify_string("columns_to_match", columns_to_match, FALSE) + verify_string("columns_to_add", columns_to_add, FALSE) return(TableHandle$new(th$internal_table_handle$exact_join( right_side$internal_table_handle, columns_to_match, columns_to_add @@ -312,8 +312,8 @@ exact_join <- function(th, right_side, columns_to_match, columns_to_add) { #' @return TableHandle reference to the new table. #' @export sort <- function(th, columns, descending = FALSE) { - verify_string_vector("columns", columns) - verify_bool_vector("descending", descending) + verify_string("columns", columns, FALSE) + verify_bool("descending", descending, FALSE) if ((length(descending) > 1) && length(descending) != length(columns)) { stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) } diff --git a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R index a00b833976b..df3fd866fdc 100644 --- a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R @@ -76,7 +76,7 @@ test_that("agg_w_avg fails nicely when 'weight_column' is a bad type", { ) expect_error( agg_w_avg(c("Multiple", "strings", "bad"), "string"), - "'weight_column' must be passed as a single string. Got a character vector of length 3 instead." + "'weight_column' must be passed as a single string. Got a string vector of length 3 instead." ) }) @@ -149,15 +149,15 @@ test_that("agg_median fails nicely when 'columns' is a bad type", { test_that("agg_percentile fails nicely when 'percentile' is bad", { expect_error( agg_percentile("string", "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class character instead." + "'percentile' must be passed as a single numeric. Got an object of class character instead." ) expect_error( agg_percentile(TRUE, "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got an object of class logical instead." + "'percentile' must be passed as a single numeric. Got an object of class logical instead." ) expect_error( agg_percentile(5, "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got a value of 5 instead." + "'percentile' must be in the interval [0, 1]. Got 'percentile' = 5 instead." ) expect_error( agg_percentile(c(5, 6, 7, 8), "string"), @@ -187,6 +187,6 @@ test_that("agg_count fails nicely when 'count_column' is a bad type", { ) expect_error( agg_count(c("Many", "strings")), - "'count_column' must be passed as a single string. Got a character vector of length 2 instead." + "'count_column' must be passed as a single string. Got a string vector of length 2 instead." ) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R index 075f550d05b..b67b3dd60b3 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R @@ -46,11 +46,11 @@ test_that("setting basic authentication with bad input types fails nicely", { ) expect_error( client_options$set_basic_authentication(c("I", "am", "a", "string"), "my_password"), - "'username' must be passed as a single string. Got a character vector of length 4 instead." + "'username' must be passed as a single string. Got a string vector of length 4 instead." ) expect_error( client_options$set_basic_authentication("my_username", c("I", "am", "a", "string")), - "'password' must be passed as a single string. Got a character vector of length 4 instead." + "'password' must be passed as a single string. Got a string vector of length 4 instead." ) }) @@ -66,11 +66,11 @@ test_that("setting custom authentication with bad input types fails nicely", { ) expect_error( client_options$set_custom_authentication(c("I", "am", "a", "string"), "my_auth_value"), - "'auth_key' must be passed as a single string. Got a character vector of length 4 instead." + "'auth_key' must be passed as a single string. Got a string vector of length 4 instead." ) expect_error( client_options$set_custom_authentication("my_auth_key", c("I", "am", "a", "string")), - "'auth_value' must be passed as a single string. Got a character vector of length 4 instead." + "'auth_value' must be passed as a single string. Got a string vector of length 4 instead." ) }) @@ -82,7 +82,7 @@ test_that("setting bad session type fails nicely", { ) expect_error( client_options$set_session_type(c("I", "am", "string")), - "'session_type' must be passed as a single string. Got a character vector of length 3 instead." + "'session_type' must be passed as a single string. Got a string vector of length 3 instead." ) }) @@ -94,7 +94,7 @@ test_that("using tls with bad input type fails nicely", { ) expect_error( client_options$use_tls(c("double", "string")), - "'root_certs' must be passed as a single string. Got a character vector of length 2 instead." + "'root_certs' must be passed as a single string. Got a string vector of length 2 instead." ) }) @@ -106,11 +106,11 @@ test_that("add_int_option with bad types fails nicely", { ) expect_error( client_options$add_int_option(c("several", "strings"), 12345), - "'opt' must be passed as a single string. Got a character vector of length 2 instead." + "'opt' must be passed as a single string. Got a string vector of length 2 instead." ) expect_error( client_options$add_int_option("option_key", "blah blah"), - "'val' must be an integer. Got an object of class character instead." + "'val' must be passed as a single numeric. Got an object of class character instead." ) expect_error( client_options$add_int_option("option_key", 12345.6789), @@ -118,7 +118,7 @@ test_that("add_int_option with bad types fails nicely", { ) expect_error( client_options$add_int_option("option_key", c(1, 2, 3, 4, 5)), - "'val' must be an integer. Got a numeric vector of length 5 instead." + "'val' must be an integer. Got 'val' = 12345.6789 instead." ) }) @@ -130,7 +130,7 @@ test_that("add_string_option with bad types fails nicely", { ) expect_error( client_options$add_string_option(c("several", "strings"), "option_val"), - "'opt' must be passed as a single string. Got a character vector of length 2 instead." + "'opt' must be passed as a single string. Got a string vector of length 2 instead." ) expect_error( client_options$add_string_option("option_key", 12345), @@ -138,7 +138,7 @@ test_that("add_string_option with bad types fails nicely", { ) expect_error( client_options$add_string_option("option_key", c("several", "many", "strings")), - "'val' must be passed as a single string. Got a character vector of length 3 instead." + "'val' must be passed as a single string. Got a string vector of length 3 instead." ) }) @@ -150,7 +150,7 @@ test_that("add_extra_header with bad types fails nicely", { ) expect_error( client_options$add_extra_header(c("several", "strings"), "header_value"), - "'header_name' must be passed as a single string. Got a character vector of length 2 instead." + "'header_name' must be passed as a single string. Got a string vector of length 2 instead." ) expect_error( client_options$add_extra_header("header_name", 12345), @@ -158,6 +158,6 @@ test_that("add_extra_header with bad types fails nicely", { ) expect_error( client_options$add_extra_header("header_name", c("several", "many", "strings")), - "'header_value' must be passed as a single string. Got a character vector of length 3 instead." + "'header_value' must be passed as a single string. Got a string vector of length 3 instead." ) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 682f9eacdd1..39beab962d6 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -174,7 +174,7 @@ test_that("client connection fails nicely with bad target but good client_option ) expect_error( client <- Client$new(target = c("hello", "my", "name", "is"), client_options = client_options), - "'target' must be passed as a single string. Got a character vector of length 4 instead." + "'target' must be passed as a single string. Got a string vector of length 4 instead." ) }) @@ -234,7 +234,7 @@ test_that("open_table fails nicely with bad inputs", { expect_error(client$open_table(""), "The table '' you're trying to pull does not exist on the server.") expect_error(client$open_table(12345), "'name' must be passed as a single string. Got an object of class numeric instead.") expect_error(client$open_table(client_options), "'name' must be passed as a single string. Got an object of class ClientOptions instead.") - expect_error(client$open_table(c("I", "am", "string")), "'name' must be passed as a single string. Got a character vector of length 3 instead.") + expect_error(client$open_table(c("I", "am", "string")), "'name' must be passed as a single string. Got a string vector of length 3 instead.") client$close() }) @@ -271,7 +271,7 @@ test_that("run_script fails nicely with bad input types", { client <- Client$new(target = "localhost:10000", client_options = client_options) expect_error(client$run_script(12345), "'script' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client$run_script(c("I", "am", "a", "string")), "'script' must be passed as a single string. Got a character vector of length 4 instead.") + expect_error(client$run_script(c("I", "am", "a", "string")), "'script' must be passed as a single string. Got a string vector of length 4 instead.") client$close() }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 50b9f569743..27ed2cb3ee8 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -37,7 +37,7 @@ setup <- function() { th4 <- client$import_table(df4) # time table to test is_static() - th5 <- client$time_table(0, 1000000000) %>% update("X = ii") + th5 <- client$time_table(1000000000) %>% update("X = ii") return(list( "client" = client, @@ -188,7 +188,7 @@ test_that("bind_to_variable fails nicely on bad inputs", { expect_error( data$th1$bind_to_variable(c("multiple", "strings")), - "'name' must be passed as a single string. Got a character vector of length 2 instead." + "'name' must be passed as a single string. Got a string vector of length 2 instead." ) expect_error( @@ -198,7 +198,7 @@ test_that("bind_to_variable fails nicely on bad inputs", { expect_error( data$th1$bind_to_variable(list("list", "of", "strings")), - "'name' must be passed as a single string. Got an object of class list instead." + "'name' must be passed as a single string. Got a string vector of length 3 instead." ) data$client$close() From 546662fefa80d89bcd3e7b887e2c2395d0faaba2 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 2 Aug 2023 13:50:04 -0500 Subject: [PATCH 40/73] Correction to helper function refactor --- R/rdeephaven/R/helper_functions.R | 15 +++++-------- .../tests/testthat/test_aggregate_wrapper.R | 4 ++-- .../testthat/test_client_options_wrapper.R | 4 ++-- .../inst/tests/testthat/test_client_wrapper.R | 22 +++++++++---------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 25cd16f0923..65b7f350332 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -24,19 +24,16 @@ verify_type <- function(arg_name, candidate, required_type, message_type_name, i } # does not attempt to verify that candidate is numeric -verify_in_range <- function(arg_name, candidate, a = NULL, b = NULL, a_open = TRUE, b_open = TRUE) { - - printed_interval = paste0(ifelse(a_open, "(", "["), ifelse(is.null(a), "-inf", as.character(a)), - ", ", ifelse(is.null(b), "inf", as.character(b)), ifelse(b_open, ")", "]")) +verify_in_range <- function(arg_name, candidate, message, a = NULL, b = NULL, a_open = TRUE, b_open = TRUE) { if(((!is.null(a)) && ((any(candidate <= a) && (a_open)) || (any(candidate < a) && (!a_open)))) || ((!is.null(b)) && ((any(candidate >= b) && (b_open)) || (any(candidate > b) && (!b_open))))) { if(length(candidate) == 1) { - stop(paste0("'", arg_name, "' must be in the interval ", printed_interval, ". Got '", arg_name, "' = ", candidate, " instead.")) + stop(paste0("'", arg_name, "' must be ", message, ". Got '", arg_name, "' = ", candidate, " instead.")) } else { - stop(paste0("Every element of '", arg_name, "' must be in the interval ", printed_interval, ". Got at least one element outside of this interval instead.")) + stop(paste0("Every element of '", arg_name, "' must be ", message, ". Got at least one element that is not ", message, " instead.")) } } } @@ -67,7 +64,7 @@ verify_numeric <- function(arg_name, candidate, is_scalar) { verify_in_unit_interval <- function(arg_name, candidate, is_scalar) { verify_numeric(arg_name, candidate, is_scalar) - verify_in_range(arg_name, candidate, a = 0, b = 1, a_open = FALSE, b_open = FALSE) + verify_in_range(arg_name, candidate, message = "between 0 and 1 inclusive", a = 0, b = 1, a_open = FALSE, b_open = FALSE) } verify_any_int <- function(arg_name, candidate, is_scalar) { @@ -78,13 +75,13 @@ verify_any_int <- function(arg_name, candidate, is_scalar) { verify_nonnegative_int <- function(arg_name, candidate, is_scalar) { verify_numeric(arg_name, candidate, is_scalar) verify_int(arg_name, candidate) - verify_in_range(arg_name, candidate, a = 0, a_open = FALSE) + verify_in_range(arg_name, candidate, message = "a nonnegative integer", a = 0, a_open = FALSE) } verify_positive_int <- function(arg_name, candidate, is_scalar) { verify_numeric(arg_name, candidate, is_scalar) verify_int(arg_name, candidate) - verify_in_range(arg_name, candidate, a = 0) + verify_in_range(arg_name, candidate, message = "a positive integer", a = 0) } strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { diff --git a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R index df3fd866fdc..66ef76537c8 100644 --- a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R @@ -157,11 +157,11 @@ test_that("agg_percentile fails nicely when 'percentile' is bad", { ) expect_error( agg_percentile(5, "string"), - "'percentile' must be in the interval [0, 1]. Got 'percentile' = 5 instead." + "'percentile' must be between 0 and 1 inclusive. Got 'percentile' = 5 instead." ) expect_error( agg_percentile(c(5, 6, 7, 8), "string"), - "'percentile' must be a numeric type between 0 and 1 inclusive. Got a numeric vector of length 4 instead." + "'percentile' must be passed as a single numeric. Got a numeric vector of length 4 instead." ) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R index b67b3dd60b3..706f5ac4f69 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R @@ -114,11 +114,11 @@ test_that("add_int_option with bad types fails nicely", { ) expect_error( client_options$add_int_option("option_key", 12345.6789), - "'val' must be an integer. Got a non-integer numeric type instead." + "'val' must be an integer. Got 'val' = 12345.6789 instead." ) expect_error( client_options$add_int_option("option_key", c(1, 2, 3, 4, 5)), - "'val' must be an integer. Got 'val' = 12345.6789 instead." + "'val' must be passed as a single numeric. Got a numeric vector of length 5 instead." ) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 39beab962d6..fb10cbc62e2 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -243,11 +243,11 @@ test_that("empty_table fails nicely with bad inputs", { client_options <- ClientOptions$new() client <- Client$new(target = "localhost:10000", client_options = client_options) - expect_error(client$empty_table(0), "'size' must be a positive integer. Got 0 instead.") - expect_error(client$empty_table(-3), "'size' must be a positive integer. Got -3 instead.") - expect_error(client$empty_table(1.2345), "'size' must be a positive integer. Got a non-integer numeric type instead.") - expect_error(client$empty_table("hello!"), "'size' must be a positive integer. Got an object of class character instead.") - expect_error(client$empty_table(c(1, 2, 3, 4)), "'size' must be a positive integer. Got a numeric vector of length 4 instead.") + expect_error(client$empty_table(0), "'size' must be a positive integer. Got 'size' = 0 instead.") + expect_error(client$empty_table(-3), "'size' must be a positive integer. Got 'size' = -3 instead.") + expect_error(client$empty_table(1.2345), "'size' must be an integer. Got 'size' = 1.2345 instead.") + expect_error(client$empty_table("hello!"), "'size' must be passed as a single numeric. Got an object of class character instead.") + expect_error(client$empty_table(c(1, 2, 3, 4)), "'size' must be passed as a single numeric. Got a numeric vector of length 4 instead.") client$close() }) @@ -256,12 +256,12 @@ test_that("time_table fails nicely with bad inputs", { client_options <- ClientOptions$new() client <- Client$new(target = "localhost:10000", client_options = client_options) - expect_error(client$time_table(1.23, 1000), "'start_time_nanos' must be an integer. Got a non-integer numeric type instead.") - expect_error(client$time_table(1000, 1.23), "'period_nanos' must be an integer. Got a non-integer numeric type instead.") - expect_error(client$time_table(c(1, 2, 3), 1000), "'start_time_nanos' must be an integer. Got a numeric vector of length 3 instead.") - expect_error(client$time_table(1000, c(1, 2, 3)), "'period_nanos' must be an integer. Got a numeric vector of length 3 instead.") - expect_error(client$time_table("hello!", 1000), "'start_time_nanos' must be an integer. Got an object of class character instead.") - expect_error(client$time_table(1000, "hello!"), "'period_nanos' must be an integer. Got an object of class character instead.") + expect_error(client$time_table(1.23, 1000), "'period_nanos' must be an integer. Got 'period_nanos' = 1.23 instead.") + expect_error(client$time_table(1000, 1.23), "'start_time_nanos' must be an integer. Got 'start_time_nanos' = 1.23 instead.") + expect_error(client$time_table(c(1, 2, 3), 1000), "'period_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") + expect_error(client$time_table(1000, c(1, 2, 3)), "'start_time_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") + expect_error(client$time_table("hello!", 1000), "'period_nanos' must be passed as a single numeric. Got an object of class character instead.") + expect_error(client$time_table(1000, "hello!"), "'start_time_nanos' must be passed as a single numeric. Got an object of class character instead.") client$close() }) From 3dfb4f5207fc30deaa0af4119f6915771ed27fbe Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 2 Aug 2023 23:38:18 +0000 Subject: [PATCH 41/73] Add new clientOptionsWrapper in S4. Does not support piping --- R/rdeephaven/NAMESPACE | 10 ++ R/rdeephaven/R/new_client_options_wrapper.R | 166 ++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 R/rdeephaven/R/new_client_options_wrapper.R diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 6d30282d7e5..f6f552a6fcc 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -52,6 +52,16 @@ export(var_by) export(view) export(w_avg_by) export(where) +exportClasses(S4ClientOptions) +exportMethods(add_extra_header) +exportMethods(add_int_option) +exportMethods(add_string_option) +exportMethods(initialize) +exportMethods(set_basic_authentication) +exportMethods(set_custom_authentication) +exportMethods(set_default_authentication) +exportMethods(set_session_type) +exportMethods(use_tls) import(Rcpp) importFrom(Rcpp,evalCpp) useDynLib(rdeephaven, .registration = TRUE) diff --git a/R/rdeephaven/R/new_client_options_wrapper.R b/R/rdeephaven/R/new_client_options_wrapper.R new file mode 100644 index 00000000000..3d5245e5be5 --- /dev/null +++ b/R/rdeephaven/R/new_client_options_wrapper.R @@ -0,0 +1,166 @@ +#' @export +setClass( + "S4ClientOptions", + representation( + .internal_rcpp_object = "Rcpp_INTERNAL_ClientOptions" + ) +) + +#' @export +setMethod( + "initialize", "S4ClientOptions", + function(.Object, ...) { + # callNextMethod calls the parent constructor, ensuring proper creation + .Object <- callNextMethod(.Object, ...) + .Object@.internal_rcpp_object <- new(INTERNAL_ClientOptions) + return(.Object) + } +) + +# ALL OF THE FOLLOWING METHODS ARE CURRENTLY ONLY CALLED FOR THEIR SIDE-EFFECTS + +setGeneric( + "set_default_authentication", + function(client_options_instance) { + return(standardGeneric("set_default_authentication")) + } +) + +#' @export +setMethod( + "set_default_authentication", "S4ClientOptions", + function(client_options_instance) { + return(client_options_instance@.internal_rcpp_object$set_default_authentication()) + } +) + +setGeneric( + "set_basic_authentication", + function(client_options_instance, ...) { + return(standardGeneric("set_basic_authentication")) + }, + signature = "client_options_instance" +) + +#' @export +setMethod( + "set_basic_authentication", + signature = c(client_options_instance = "S4ClientOptions"), + function(client_options_instance, username, password) { + verify_string("username", username, TRUE) + verify_string("password", password, TRUE) + return(client_options_instance@.internal_rcpp_object$set_basic_authentication(username, password)) + } +) + +setGeneric( + "set_custom_authentication", + function(client_options_instance, ...) { + return(standardGeneric("set_custom_authentication")) + }, + signature = "client_options_instance" +) + +#' @export +setMethod( + "set_custom_authentication", + signature = c(client_options_instance = "S4ClientOptions"), + function(client_options_instance, auth_key, auth_value) { + verify_string("auth_key", auth_key, TRUE) + verify_string("auth_value", auth_value, TRUE) + return(client_options_instance@.internal_rcpp_object$set_custom_authentication(auth_key, auth_value)) + } +) + +setGeneric( + "set_session_type", + function(client_options_instance, ...) { + return(standardGeneric("set_session_type")) + }, + signature = "client_options_instance" +) + +#' @export +setMethod( + "set_session_type", + signature = c(client_options_instance = "S4ClientOptions"), + function(client_options_instance, session_type) { + verify_string("session_type", session_type, TRUE) + return(client_options_instance@.internal_rcpp_object$set_session_type(session_type)) + } +) + +setGeneric( + "use_tls", + function(client_options_instance, ...) { + return(standardGeneric("use_tls")) + }, + signature = "client_options_instance" +) + +#' @export +setMethod( + "use_tls", + signature = c(client_options_instance = "S4ClientOptions"), + function(client_options_instance, root_certs = "") { + verify_string("root_certs", root_certs, TRUE) + return(client_options_instance@.internal_rcpp_object$set_tls_root_certs(root_certs)) + } +) + +setGeneric( + "add_int_option", + function(client_options_instance, ...) { + return(standardGeneric("add_int_option")) + }, + signature = "client_options_instance" +) + +#' @export +setMethod( + "add_int_option", + signature = c(client_options_instance = "S4ClientOptions"), + function(client_options_instance, opt, val) { + verify_string("opt", opt, TRUE) + verify_any_int("val", val, TRUE) + return(client_options_instance@.internal_rcpp_object$add_int_option(opt, val)) + } +) + +setGeneric( + "add_string_option", + function(client_options_instance, ...) { + return(standardGeneric("add_string_option")) + }, + signature = "client_options_instance" +) + +#' @export +setMethod( + "add_string_option", + signature = c(client_options_instance = "S4ClientOptions"), + function(client_options_instance, opt, val) { + verify_string("opt", opt, TRUE) + verify_string("val", val, TRUE) + return(client_options_instance@.internal_rcpp_object$add_string_option(opt, val)) + } +) + +setGeneric( + "add_extra_header", + function(client_options_instance, ...) { + return(standardGeneric("add_extra_header")) + }, + signature = "client_options_instance" +) + +#' @export +setMethod( + "add_extra_header", + signature = c(client_options_instance = "S4ClientOptions"), + function(client_options_instance, opt, val) { + verify_string("header_name", header_name, TRUE) + verify_string("header_value", header_value, TRUE) + return(client_options_instance@.internal_rcpp_object$add_extra_header(opt, val)) + } +) From 3b0d89d099f8553d071add9eb1ad2cb10c36613b Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Thu, 3 Aug 2023 21:52:47 +0000 Subject: [PATCH 42/73] More rewrite --- R/rdeephaven/DESCRIPTION | 4 +- R/rdeephaven/NAMESPACE | 113 ++-- R/rdeephaven/R/aggregate_wrapper.R | 98 ---- R/rdeephaven/R/client_options_wrapper.R | 120 ---- R/rdeephaven/R/client_wrapper.R | 142 ----- R/rdeephaven/R/helper_functions.R | 4 + R/rdeephaven/R/new_aggregate_wrapper.R | 89 +++ R/rdeephaven/R/new_client_options_wrapper.R | 40 +- R/rdeephaven/R/new_client_wrapper.R | 183 ++++++ R/rdeephaven/R/new_table_handle_wrapper.R | 127 +++++ R/rdeephaven/R/new_table_ops.R | 531 ++++++++++++++++++ R/rdeephaven/R/table_handle_wrapper.R | 149 ----- R/rdeephaven/R/table_ops.R | 321 ----------- .../inst/tests/testthat/test_table_ops.R | 72 +-- R/rdeephaven/man/Client.Rd | 161 ------ R/rdeephaven/man/ClientOptions.Rd | 200 ------- R/rdeephaven/man/TableHandle.Rd | 149 ----- 17 files changed, 1055 insertions(+), 1448 deletions(-) delete mode 100644 R/rdeephaven/R/aggregate_wrapper.R delete mode 100644 R/rdeephaven/R/client_options_wrapper.R delete mode 100644 R/rdeephaven/R/client_wrapper.R create mode 100644 R/rdeephaven/R/new_aggregate_wrapper.R create mode 100644 R/rdeephaven/R/new_client_wrapper.R create mode 100644 R/rdeephaven/R/new_table_handle_wrapper.R create mode 100644 R/rdeephaven/R/new_table_ops.R delete mode 100644 R/rdeephaven/R/table_handle_wrapper.R delete mode 100644 R/rdeephaven/R/table_ops.R delete mode 100644 R/rdeephaven/man/Client.Rd delete mode 100644 R/rdeephaven/man/ClientOptions.Rd delete mode 100644 R/rdeephaven/man/TableHandle.Rd diff --git a/R/rdeephaven/DESCRIPTION b/R/rdeephaven/DESCRIPTION index 079df08c5ed..21bbf3bcd7b 100644 --- a/R/rdeephaven/DESCRIPTION +++ b/R/rdeephaven/DESCRIPTION @@ -13,8 +13,8 @@ Description: The `rdeephaven` package provides an R API for communicating with t and bind it to a server-side variable so you can access it from any Deephaven client. Finally, you can run Python or Groovy scripts on the Deephaven server, so long as your server is equipped with that capability. License: Apache License (== 2.0) -Depends: R (> 4.1.2), Rcpp (>= 1.0.10), arrow (>= 12.0.0), R6 (>= 2.5.0), dplyr (>= 1.1.0) -Imports: Rcpp (>= 1.0.10), arrow (>= 12.0.0), R6 (>= 2.5.0), dplyr (>= 1.1.0) +Depends: R (> 4.1.2), Rcpp (>= 1.0.10), arrow (>= 12.0.0), magrittr (>= 2.0.0) +Imports: Rcpp (>= 1.0.10), arrow (>= 12.0.0), magrittr (>= 2.0.0) LinkingTo: Rcpp Suggests: testthat (>= 3.0.0) Config/testthat/edition: 3 diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index f6f552a6fcc..65ca67503d6 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -1,67 +1,78 @@ # Generated by roxygen2: do not edit by hand -S3method(as.data.frame,TableHandle) -S3method(as_arrow_table,TableHandle) -S3method(as_tibble,TableHandle) -S3method(head,TableHandle) -S3method(print,TableHandle) -S3method(rbind,TableHandle) -S3method(tail,TableHandle) -export(Aggregation) -export(Client) -export(ClientOptions) -export(TableHandle) -export(abs_sum_by) -export(agg_abs_sum) -export(agg_avg) -export(agg_by) -export(agg_count) -export(agg_first) -export(agg_last) -export(agg_max) -export(agg_median) -export(agg_min) -export(agg_percentile) -export(agg_std) -export(agg_sum) -export(agg_var) -export(agg_w_avg) -export(avg_by) -export(count_by) -export(cross_join) -export(drop_columns) -export(exact_join) -export(first_by) -export(group_by) -export(head_by) -export(last_by) -export(max_by) -export(median_by) -export(min_by) -export(natural_join) -export(percentile_by) -export(select) +export(s4_agg_abs_sum) +export(s4_agg_avg) +export(s4_agg_count) +export(s4_agg_first) +export(s4_agg_last) +export(s4_agg_max) +export(s4_agg_median) +export(s4_agg_min) +export(s4_agg_percentile) +export(s4_agg_std) +export(s4_agg_sum) +export(s4_agg_var) +export(s4_agg_w_avg) export(sort) -export(std_by) -export(sum_by) -export(tail_by) -export(ungroup) -export(update) -export(update_view) -export(var_by) -export(view) -export(w_avg_by) -export(where) +exportClasses(S4Aggregation) +exportClasses(S4Client) exportClasses(S4ClientOptions) +exportClasses(S4TableHandle) +exportMethods(abs_sum_by) exportMethods(add_extra_header) exportMethods(add_int_option) exportMethods(add_string_option) +exportMethods(agg_by) +exportMethods(as.data.frame) +exportMethods(as_arrow_record_batch_stream_reader) +exportMethods(as_arrow_table) +exportMethods(as_tibble) +exportMethods(avg_by) +exportMethods(bind_to_variable) +exportMethods(close) +exportMethods(connect) +exportMethods(count_by) +exportMethods(cross_join) +exportMethods(drop_columns) +exportMethods(empty_table) +exportMethods(exact_join) +exportMethods(first_by) +exportMethods(group_by) +exportMethods(head) +exportMethods(head_by) +exportMethods(import_table) exportMethods(initialize) +exportMethods(is_static) +exportMethods(last_by) +exportMethods(max_by) +exportMethods(median_by) +exportMethods(min_by) +exportMethods(natural_join) +exportMethods(open_table) +exportMethods(percentile_by) +exportMethods(run_script) +exportMethods(select) exportMethods(set_basic_authentication) exportMethods(set_custom_authentication) exportMethods(set_default_authentication) exportMethods(set_session_type) +exportMethods(sort) +exportMethods(std_by) +exportMethods(sum_by) +exportMethods(tail) +exportMethods(tail_by) +exportMethods(time_table) +exportMethods(ungroup) +exportMethods(update) +exportMethods(update_view) exportMethods(use_tls) +exportMethods(var_by) +exportMethods(view) +exportMethods(w_avg_by) +exportMethods(where) import(Rcpp) importFrom(Rcpp,evalCpp) +importFrom(arrow,RecordBatchStreamReader) +importFrom(arrow,as_arrow_table) +importFrom(dplyr,as_tibble) useDynLib(rdeephaven, .registration = TRUE) diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R deleted file mode 100644 index 3219f65befe..00000000000 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ /dev/null @@ -1,98 +0,0 @@ -#' @export -Aggregation <- R6Class("Aggregation", - cloneable = FALSE, - public = list( - - #' @description - #' Create an Aggregation instance. - initialize = function(aggregation) { - if (class(aggregation) != "Rcpp_INTERNAL_Aggregate") { - stop("'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead.") - } - self$internal_aggregation <- aggregation - }, - internal_aggregation = NULL - ) -) - -### All of the functions below return an instance of the above class - -#' @export -agg_first <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_first(columns))) -} - -#' @export -agg_last <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_last(columns))) -} - -#' @export -agg_min <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_min(columns))) -} - -#' @export -agg_max <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_max(columns))) -} - -#' @export -agg_sum <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_sum(columns))) -} - -#' @export -agg_abs_sum <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_abs_sum(columns))) -} - -#' @export -agg_avg <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_avg(columns))) -} - -#' @export -agg_w_avg <- function(weight_column, columns = character()) { - verify_string("weight_column", weight_column, TRUE) - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_w_avg(weight_column, columns))) -} - -#' @export -agg_median <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_median(columns))) -} - -#' @export -agg_var <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_var(columns))) -} - -#' @export -agg_std <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_std(columns))) -} - -#' @export -agg_percentile <- function(percentile, columns = character()) { - verify_in_unit_interval("percentile", percentile, TRUE) - verify_string("columns", columns, FALSE) - return(Aggregation$new(INTERNAL_percentile(percentile, columns))) -} - -#' @export -agg_count <- function(count_column) { - verify_string("count_column", count_column, TRUE) - return(Aggregation$new(INTERNAL_count(count_column))) -} diff --git a/R/rdeephaven/R/client_options_wrapper.R b/R/rdeephaven/R/client_options_wrapper.R deleted file mode 100644 index 93e164377be..00000000000 --- a/R/rdeephaven/R/client_options_wrapper.R +++ /dev/null @@ -1,120 +0,0 @@ -#' @title Deephaven ClientOptions -#' @description Client options provide a simple interface to the Deephaven server's authentication protocols. -#' This makes it easy to connect to a Deephaven server with any flavor of authentication, and shields the API from -#' any future changes to the underlying implementation. -#' -#' Currently, three different kinds of authentication that a Deephaven server might be using are suported: -#' -#' - "default": Default (or anonymous) authentication does not require any username or password. If -#' running the Deephaven server locally, this is probably the kind of authentication needed. -#' -#' - "basic": Basic authentication requires a standard username and password pair. -#' -#' - "custom": Custom authentication requires general key-value pairs. -#' -#' In addition to setting the authentication parameters when connecting to a client, a console can be -#' started in one of our supported server languages. Python and Groovy are currently supported, and the -#' user must ensure that the server being connected to was started with support for the desired console language. -#' -#' @usage NULL -#' @format NULL -#' @docType class -#' -#' @examples -#' -#' # connect to a Deephaven server with a Python console running on "localhost:10000" using anonymous 'default' authentication -#' client_options <- ClientOptions$new() -#' client <- Client$new(target = "localhost:10000", client_options = client_options) -#' -#' # connect to a secure Deephaven server with a Groovy console using username/password authentication -#' client_options <- ClientOptions$new() -#' client_options$set_basic_authentication(username = "user", password = "p@ssw0rd123") -#' client_options$set_session_type("groovy") -#' client <- Client$new(target = "url/to/secure/server", client_options = client_options) - -#' @export -ClientOptions <- R6Class("ClientOptions", - cloneable = FALSE, - public = list( - - #' @description - #' Create a ClientOptions instance. This will default to using default (anonymous) authentication and a Python console. - initialize = function() { - self$internal_client_options <- new(INTERNAL_ClientOptions) - }, - - #' @description - #' Use default (anonymous) authentication. If running a Deephaven server locally, this is likely the kind of authentication needed. - set_default_authentication = function() { - self$internal_client_options$set_default_authentication() - }, - - #' @description - #' Use basic (username/password based) authentication. - #' @param username Username of the account to use for authentication, supplied as a string. - #' @param password Password of the account, supplied as a string. - set_basic_authentication = function(username, password) { - verify_string("username", username, TRUE) - verify_string("password", password, TRUE) - self$internal_client_options$set_basic_authentication(username, password) - }, - - #' @description - #' Use custom (general key/value based) authentication. - #' @param auth_key Key to use for authentication, supplied as a string. - #' @param auth_value Value to use for authentication, supplied as a string. - set_custom_authentication = function(auth_key, auth_value) { - verify_string("auth_key", auth_key, TRUE) - verify_string("auth_value", auth_value, TRUE) - self$internal_client_options$set_custom_authentication(auth_key, auth_value) - }, - - #' @description - #' Set the session type of the console (e.g., "python", "groovy", etc.). The session type must be supported on the server. - #' @param session_type Desired language of the console. "python", "groovy", etc. - set_session_type = function(session_type) { - verify_string("session_type", session_type, TRUE) - self$internal_client_options$set_session_type(session_type) - }, - - #' @description - #' Use the TLS protocol in authentication and subsequent communication. - #' @param root_certs Optional PEM-encoded certificate root for server connections. Defaults to system defaults. - use_tls = function(root_certs = "") { - verify_string("root_certs", root_certs, TRUE) - self$internal_client_options$set_use_tls(TRUE) - self$internal_client_options$set_tls_root_certs(root_certs) - }, - - - #' Adds an int-valued option for the configuration of the underlying gRPC channels. - #' @param opt The option key. - #' @param val The option value, assumed to be a scalar integer. - add_int_option = function(opt, val) { - verify_string("opt", opt, TRUE) - verify_any_int("val", val, TRUE) - self$internal_client_options$add_int_option(opt, val) - }, - - #' @description - #' Adds a string-valued option for the configuration of the underlying gRPC channels. - #' @param opt The option key. - #' @param val The option valiue. - add_string_option = function(opt, val) { - verify_string("opt", opt, TRUE) - verify_string("val", val, TRUE) - self$internal_client_options$add_string_option(opt, val) - }, - - #' @description - #' Adds an extra header with a constant name and value to be sent with every outgoing server request. - #' @param header_name The header name - #' @param header_value The header value - add_extra_header = function(header_name, header_value) { - verify_string("header_name", header_name, TRUE) - verify_string("header_value", header_value, TRUE) - self$internal_client_options$add_extra_header(header_name, header_value) - }, - internal_client_options = NULL - ) -) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R deleted file mode 100644 index 3f9d78e9178..00000000000 --- a/R/rdeephaven/R/client_wrapper.R +++ /dev/null @@ -1,142 +0,0 @@ -#' @title The Deephaven Client -#' @description The Deephaven Client class is responsible for establishing and maintaining -#' a connection to a running Deephaven server and facilitating basic server requests. -#' -#' @usage NULL -#' @format NULL -#' @docType class -#' -#' @examples -#' -#' # connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication -#' client_options <- ClientOptions$new() -#' client <- Client$new(target = "localhost:10000", client_options = client_options) -#' -#' # open a table that already exists on the server -#' new_table_handle1 <- client$open_table("table_on_the_server") -#' -#' # create a new dataframe, import onto the server, and retrieve a reference -#' new_data_frame <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) -#' new_table_handle2 <- client$import_table(new_data_frame) -#' -#' # run a python script on the server (default client options specify a Python console) -#' client$run_script("print([i for i in range(10)])") - -#' @export -Client <- R6Class("Client", - cloneable = FALSE, - public = list( - - #' @description - #' Connect to a running Deephaven server. - #' @param target The address of the Deephaven server. - #' @param client_options ClientOptions instance with the parameters needed to connect to the server. - #' See ?ClientOptions for more information. - initialize = function(target, client_options) { - verify_string("target", target, TRUE) - if (first_class(client_options) != "ClientOptions") { - stop(paste("'client_options' should be a Deephaven ClientOptions object. Got an object of type", first_class(client_options), "instead.")) - } - private$internal_client <- new(INTERNAL_Client, - target = target, - client_options = client_options$internal_client_options - ) - }, - - #' @description - #' Opens a table named 'name' from the server if it exists. - #' @param name Name of the table to open from the server, passed as a string. - #' @return TableHandle reference to the requested table. - open_table = function(name) { - verify_string("name", name, TRUE) - if (!private$check_for_table(name)) { - stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) - } - return(TableHandle$new(private$internal_client$open_table(name))) - }, - - #' @description - #' Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. - #' @param size Number of rows in the empty table. - #' @return TableHandle reference to the new table, which has not yet been named on the server. - #' See TableHandle$bind_to_variable() for naming a new table on the server. - empty_table = function(size) { - verify_positive_int("size", size, TRUE) - return(TableHandle$new(private$internal_client$empty_table(size))) - }, - - #' @description - #' Creates a ticking table. - #' @param start_time_nanos When the table should start ticking (in units of nanoseconds since the epoch). - #' @param period_nanos Table ticking frequency (in nanoseconds). - #' @return TableHandle reference to the new table, which has not yet been named on the server. - #' See TableHandle$bind_to_variable() for naming a new table on the server. - time_table = function(period_nanos, start_time_nanos = 0) { - verify_any_int("period_nanos", period_nanos, TRUE) - verify_any_int("start_time_nanos", start_time_nanos, TRUE) - return(TableHandle$new(private$internal_client$time_table(start_time_nanos, period_nanos))) - }, - - #' @description - #' Imports a new table to the Deephaven server. Note that this new table is not automatically bound to - #' a variable name on the server. See `?TableHandle` for more information. - #' @param table_object An R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow RecordBatchReader - #' containing the data to import to the server. - #' @return TableHandle reference to the new table. - import_table = function(table_object) { - table_object_class <- class(table_object) - if (table_object_class[[1]] == "data.frame") { - return(TableHandle$new(private$df_to_dh_table(table_object))) - } - if (table_object_class[[1]] == "tbl_df") { - return(TableHandle$new(private$tibble_to_dh_table(table_object))) - } else if (table_object_class[[1]] == "RecordBatchReader") { - return(TableHandle$new(private$rbr_to_dh_table(table_object))) - } else if ((length(table_object_class) == 4 && - table_object_class[[1]] == "Table" && - table_object_class[[3]] == "ArrowObject")) { - return(TableHandle$new(private$arrow_to_dh_table(table_object))) - } else { - stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], " instead.")) - } - }, - - #' @description - #' Runs a script on the server. The script must be in the language that the server console was started with. - #' @param script Code to be executed on the server, passed as a string. - run_script = function(script) { - verify_string("script", script, TRUE) - private$internal_client$run_script(script) - }, - - #' @description - #' Closes the client connection and all associated state. Once this is called, no TableHandles pulled from - #' this client connection will remain valid. - close = function() { - private$internal_client$close() - } - ), - private = list( - check_for_table = function(name) { - return(private$internal_client$check_for_table(name)) - }, - rbr_to_dh_table = function(rbr) { - ptr <- private$internal_client$new_arrow_array_stream_ptr() - rbr$export_to_c(ptr) - return(private$internal_client$new_table_from_arrow_array_stream_ptr(ptr)) - }, - arrow_to_dh_table = function(arrow_tbl) { - rbr <- as_record_batch_reader(arrow_tbl) - return(private$rbr_to_dh_table(rbr)) - }, - tibble_to_dh_table = function(tibbl) { - arrow_tbl <- arrow_table(tibbl) - return(private$arrow_to_dh_table(arrow_tbl)) - }, - df_to_dh_table = function(data_frame) { - arrow_tbl <- arrow_table(data_frame) - return(private$arrow_to_dh_table(arrow_tbl)) - }, - internal_client = NULL - ) -) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 65b7f350332..a743f4ee852 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -91,3 +91,7 @@ strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { strip_r6_wrapping_from_table_handle <- function(r6_table_handle) { return(r6_table_handle$internal_table_handle) } + +strip_s4_wrapping <- function(s4_object) { + return(s4_object@.internal_rcpp_object) +} diff --git a/R/rdeephaven/R/new_aggregate_wrapper.R b/R/rdeephaven/R/new_aggregate_wrapper.R new file mode 100644 index 00000000000..51863c99f76 --- /dev/null +++ b/R/rdeephaven/R/new_aggregate_wrapper.R @@ -0,0 +1,89 @@ +#' @export +setClass( + "S4Aggregation", + representation( + .internal_rcpp_object = "Rcpp_INTERNAL_Aggregate" + ) +) + +### All of the functions below return an instance of the above class + +#' @export +s4_agg_first <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_first(columns))) +} + +#' @export +s4_agg_last <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_last(columns))) +} + +#' @export +s4_agg_min <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_min(columns))) +} + +#' @export +s4_agg_max <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_max(columns))) +} + +#' @export +s4_agg_sum <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_sum(columns))) +} + +#' @export +s4_agg_abs_sum <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_abs_sum(columns))) +} + +#' @export +s4_agg_avg <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_avg(columns))) +} + +#' @export +s4_agg_w_avg <- function(weight_column, columns = character()) { + verify_string("weight_column", weight_column, TRUE) + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_w_avg(weight_column, columns))) +} + +#' @export +s4_agg_median <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_median(columns))) +} + +#' @export +s4_agg_var <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_var(columns))) +} + +#' @export +s4_agg_std <- function(columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_std(columns))) +} + +#' @export +s4_agg_percentile <- function(percentile, columns = character()) { + verify_in_unit_interval("percentile", percentile, TRUE) + verify_string("columns", columns, FALSE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_percentile(percentile, columns))) +} + +#' @export +s4_agg_count <- function(count_column) { + verify_string("count_column", count_column, TRUE) + return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_count(count_column))) +} \ No newline at end of file diff --git a/R/rdeephaven/R/new_client_options_wrapper.R b/R/rdeephaven/R/new_client_options_wrapper.R index 3d5245e5be5..7c3f832d887 100644 --- a/R/rdeephaven/R/new_client_options_wrapper.R +++ b/R/rdeephaven/R/new_client_options_wrapper.R @@ -9,10 +9,10 @@ setClass( #' @export setMethod( "initialize", "S4ClientOptions", - function(.Object, ...) { - # callNextMethod calls the parent constructor, ensuring proper creation - .Object <- callNextMethod(.Object, ...) - .Object@.internal_rcpp_object <- new(INTERNAL_ClientOptions) + function(.Object) { + internal_client_options <- new(INTERNAL_ClientOptions) + .Object <- callNextMethod(.Object, + .internal_rcpp_object = internal_client_options) return(.Object) } ) @@ -23,12 +23,14 @@ setGeneric( "set_default_authentication", function(client_options_instance) { return(standardGeneric("set_default_authentication")) - } + }, + signature = c("client_options_instance") ) #' @export setMethod( - "set_default_authentication", "S4ClientOptions", + "set_default_authentication", + signature = c(client_options_instance = "S4ClientOptions"), function(client_options_instance) { return(client_options_instance@.internal_rcpp_object$set_default_authentication()) } @@ -36,10 +38,10 @@ setMethod( setGeneric( "set_basic_authentication", - function(client_options_instance, ...) { + function(client_options_instance, username, password) { return(standardGeneric("set_basic_authentication")) }, - signature = "client_options_instance" + signature = c("client_options_instance", "username", "password") ) #' @export @@ -55,10 +57,10 @@ setMethod( setGeneric( "set_custom_authentication", - function(client_options_instance, ...) { + function(client_options_instance, auth_key, auth_value) { return(standardGeneric("set_custom_authentication")) }, - signature = "client_options_instance" + signature = c("client_options_instance", "auth_key", "auth_value") ) #' @export @@ -74,10 +76,10 @@ setMethod( setGeneric( "set_session_type", - function(client_options_instance, ...) { + function(client_options_instance, session_type) { return(standardGeneric("set_session_type")) }, - signature = "client_options_instance" + signature = c("client_options_instance", "session_type") ) #' @export @@ -110,10 +112,10 @@ setMethod( setGeneric( "add_int_option", - function(client_options_instance, ...) { + function(client_options_instance, opt, val) { return(standardGeneric("add_int_option")) }, - signature = "client_options_instance" + signature = c("client_options_instance", "opt", "val") ) #' @export @@ -129,10 +131,10 @@ setMethod( setGeneric( "add_string_option", - function(client_options_instance, ...) { + function(client_options_instance, opt, val) { return(standardGeneric("add_string_option")) }, - signature = "client_options_instance" + signature = c("client_options_instance", "opt", "val") ) #' @export @@ -148,17 +150,17 @@ setMethod( setGeneric( "add_extra_header", - function(client_options_instance, ...) { + function(client_options_instance, header_name, header_val) { return(standardGeneric("add_extra_header")) }, - signature = "client_options_instance" + signature = c("client_options_instance", "header_name", "header_val") ) #' @export setMethod( "add_extra_header", signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, opt, val) { + function(client_options_instance, header_name, header_val) { verify_string("header_name", header_name, TRUE) verify_string("header_value", header_value, TRUE) return(client_options_instance@.internal_rcpp_object$add_extra_header(opt, val)) diff --git a/R/rdeephaven/R/new_client_wrapper.R b/R/rdeephaven/R/new_client_wrapper.R new file mode 100644 index 00000000000..a7041969807 --- /dev/null +++ b/R/rdeephaven/R/new_client_wrapper.R @@ -0,0 +1,183 @@ +#' @export +setClass( + "S4Client", + representation( + .internal_rcpp_object = "Rcpp_INTERNAL_Client" + ) +) + +setGeneric( + "connect", + function(target, client_options) { + return(standardGeneric("connect")) + }, + signature = c("target", "client_options") +) + +#' @export +setMethod( + "connect", + signature = c(target = "character", client_options = "S4ClientOptions"), + function(target, client_options) { + internal_client <- new(INTERNAL_Client, + target = target, + client_options = client_options@.internal_rcpp_object + ) + return(new("S4Client", .internal_rcpp_object = internal_client)) + } +) + +### HELPER FUNCTIONS ### +# These functions return RC objects returned by Rcpp without wrapping them in S4 + +check_for_table <- function(client, name) { + return(client@.internal_rcpp_object$check_for_table(name)) +} + +rbr_to_dh_table <- function(client, rbr) { + ptr <- client@.internal_rcpp_object$new_arrow_array_stream_ptr() + rbr$export_to_c(ptr) + return(client@.internal_rcpp_object$new_table_from_arrow_array_stream_ptr(ptr)) +} + +arrow_to_dh_table <- function(client, arrow_tbl) { + rbr <- as_record_batch_reader(arrow_tbl) + return(rbr_to_dh_table(client, rbr)) +} + +tibble_to_dh_table <- function(client, tibbl) { + arrow_tbl <- arrow_table(tibbl) + return(arrow_to_dh_table(client, arrow_tbl)) +} + +df_to_dh_table <- function(client, data_frame) { + arrow_tbl <- arrow_table(data_frame) + return(arrow_to_dh_table(client, arrow_tbl)) +} + +### USER-FACING METHODS ### + +setGeneric( + "open_table", + function(client_instance, name) { + return(standardGeneric("open_table")) + }, + signature = c("client_instance", "name") +) + +#' @export +setMethod( + "open_table", + signature = c(client_instance = "S4Client"), + function(client_instance, name) { + verify_string("name", name, TRUE) + if (!check_for_table(client_instance, name)) { + stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) + } + return(new("S4TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$open_table(name))) + } +) + +setGeneric( + "empty_table", + function(client_instance, size) { + return(standardGeneric("empty_table")) + }, + signature = c("client_instance", "size") +) + +#' @export +setMethod( + "empty_table", + signature = c(client_instance = "S4Client"), + function(client_instance, size) { + verify_positive_int("size", size, TRUE) + return(new("S4TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$empty_table(size))) + } +) + +setGeneric( + "time_table", + function(client_instance, ...) { + return(standardGeneric("time_table")) + }, + signature = "client_instance" +) + +#' @export +setMethod( + "time_table", + signature = c(client_instance = "S4Client"), + function(client_instance, period_nanos, start_time_nanos = 0) { + verify_any_int("period_nanos", period_nanos, TRUE) + verify_any_int("start_time_nanos", start_time_nanos, TRUE) + return(new("S4TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$time_table(start_time_nanos, period_nanos))) + } +) + +setGeneric( + "import_table", + function(client_instance, table_object) { + return(standardGeneric("import_table")) + }, + signature = c("client_instance", "table_object") +) + +#' @export +setMethod( + "import_table", + signature = c(client_instance = "S4Client"), + function(client_instance, table_object) { + + table_object_class <- class(table_object) + + if (table_object_class[[1]] == "data.frame") { + rcpp_dh_table <- df_to_dh_table(client_instance, table_object) + } + else if (table_object_class[[1]] == "tbl_df") { + rcpp_dh_table <- tibble_to_dh_table(client_instance, table_object) + } + else if (table_object_class[[1]] == "RecordBatchReader") { + rcpp_dh_table <- rbr_to_dh_table(client_instance, table_object) + } + else if ((length(table_object_class) == 4 && + table_object_class[[1]] == "Table" && + table_object_class[[3]] == "ArrowObject")) { + rcpp_dh_table <- arrow_to_dh_table(client_instance, table_object) + } + else { + stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], " instead.")) + } + return(new("S4TableHandle", .internal_rcpp_object = rcpp_dh_table)) + } +) + +setGeneric( + "run_script", + function(client_instance, script) { + return(standardGeneric("run_script")) + }, + signature = c("client_instance", "script") +) + +#' @export +setMethod( + "run_script", + signature = c(client_instance = "S4Client"), + function(client_instance, script) { + verify_string("script", script, TRUE) + client_instance@.internal_rcpp_object$run_script(script) + return(NULL) + } +) + +# do not need to set generic for 'close', as it already exists as a generic +#' @export +setMethod( + "close", + signature = c(con = "S4Client"), + function(con) { + con@.internal_rcpp_object$close() + return(NULL) + } +) diff --git a/R/rdeephaven/R/new_table_handle_wrapper.R b/R/rdeephaven/R/new_table_handle_wrapper.R new file mode 100644 index 00000000000..661e7a25511 --- /dev/null +++ b/R/rdeephaven/R/new_table_handle_wrapper.R @@ -0,0 +1,127 @@ +#' @importFrom arrow as_arrow_table RecordBatchStreamReader +#' @importFrom dplyr as_tibble + +#' @export +setClass( + "S4TableHandle", + representation( + .internal_rcpp_object = "Rcpp_INTERNAL_TableHandle" + ) +) + +### TABLEHANDLE PROPERTIES + +setGeneric( + "is_static", + function(table_handle_instance) { + return(standardGeneric("is_static")) + }, + signature = c("table_handle_instance") +) + +#' @export +setMethod( + "is_static", + signature = c(table_handle_instance = "S4TableHandle"), + function(table_handle_instance) { + return(table_handle_instance@.internal_rcpp_object$is_static()) + } +) + +#' @export +setMethod( + "head", + signature = c(x = "S4TableHandle"), + function(x, n, ...) { + verify_positive_int("n", n, TRUE) + return(new("S4TableHandle", .internal_rcpp_object = x@.internal_rcpp_object$head(n))) + } +) + +#' @export +setMethod( + "tail", + signature = c(x = "S4TableHandle"), + function(x, n, ...) { + print("I'm here!") + verify_positive_int("n", n, TRUE) + return(new("S4TableHandle", .internal_rcpp_object = x@.internal_rcpp_object$tail(n))) + } +) + +# TODO: Implement nrow, ncol, dim + +### TABLEHANDLE CONVERSIONS ### + +# could potentially be implemented by other packages +setGeneric( + "as_arrow_record_batch_stream_reader", + function(x, ...) { + return(standardGeneric("as_arrow_record_batch_stream_reader")) + }, + signature = c("x") +) + +#' @export +setMethod( + "as_arrow_record_batch_stream_reader", + signature = c(x = "S4TableHandle"), + function(x, ...) { + ptr <- x@.internal_rcpp_object$get_arrow_array_stream_ptr() + rbsr <- RecordBatchStreamReader$import_from_c(ptr) + return(rbsr) + } +) + +#' @export +setMethod( + "as_arrow_table", + signature = c(x = "S4TableHandle"), + function(x, ...) { + rbsr <- as_arrow_record_batch_stream_reader(x) + arrow_tbl <- rbsr$read_table() + return(arrow_tbl) + } +) + +#' @export +setMethod( + "as_tibble", + signature = c(x = "S4TableHandle"), + function(x, ...) { + rbsr <- as_arrow_record_batch_stream_reader(x) + arrow_tbl <- rbsr$read_table() + return(as_tibble(arrow_tbl)) + } +) + +#' @export +setMethod( + "as.data.frame", + signature = c(x = "S4TableHandle"), + function(x, ...) { + arrow_tbl <- as_arrow_table(x) + return(as.data.frame(as.data.frame(arrow_tbl))) + } +) + +### TABLEHANDLE OPERATIONS ### + +setGeneric( + "bind_to_variable", + function(table_handle_instance, name) { + return(standardGeneric("bind_to_variable")) + }, + signature = c("table_handle_instance", "name") +) + +#' @export +setMethod( + "bind_to_variable", + signature = c(table_handle_instance = "S4TableHandle"), + function(table_handle_instance, name) { + verify_string("name", name, TRUE) + table_handle_instance@.internal_rcpp_object$bind_to_variable(name) + return(NULL) + } +) \ No newline at end of file diff --git a/R/rdeephaven/R/new_table_ops.R b/R/rdeephaven/R/new_table_ops.R new file mode 100644 index 00000000000..6fdd695e9ce --- /dev/null +++ b/R/rdeephaven/R/new_table_ops.R @@ -0,0 +1,531 @@ +setGeneric( + "select", + function(table_handle, columns, ...) { + return(standardGeneric("select")) + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "select", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$select(columns))) + } +) + +setGeneric( + "view", + function(table_handle, columns, ...) { + return(standardGeneric("view")) + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "view", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$view(columns))) + } +) + +setGeneric( + "update", + function(table_handle, columns, ...) { + standardGeneric("update") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "update", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update(columns))) + } +) + +setGeneric( + "update_view", + function(table_handle, columns, ...) { + standardGeneric("update_view") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "update_view", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update_view(columns))) + } +) + +setGeneric( + "drop_columns", + function(table_handle, columns, ...) { + standardGeneric("drop_columns") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "drop_columns", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$drop_columns(columns))) + } +) + +setGeneric( + "where", + function(table_handle, condition, ...) { + standardGeneric("where") + }, + signature = c("table_handle", "condition") +) + +#' @export +setMethod( + "where", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, condition) { + verify_string("condition", condition, TRUE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$where(condition))) + } +) + +setGeneric( + "group_by", + function(table_handle, columns, ...) { + standardGeneric("group_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "group_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$group_by(columns))) + } +) + +setGeneric( + "ungroup", + function(table_handle, columns, ...) { + standardGeneric("ungroup") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "ungroup", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$ungroup(columns))) + } +) + +setGeneric( + "agg_by", + function(table_handle, aggregations, columns, ...) { + standardGeneric("agg_by") + }, + signature = c("table_handle", "aggregations", "columns") +) + +# WILL MOT WORK YET +#' @export +setMethod( + "agg_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, aggregations, columns = character()) { + verify_type("aggregations", aggregations, "Aggregation", "Deephaven Aggregation", FALSE) + verify_string("columns", columns, FALSE) + aggregations <- c(aggregations) + unwrapped_aggregations <- lapply(aggregations, strip_s4_wrapping) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$agg_by(unwrapped_aggregations, columns))) + } +) + +setGeneric( + "first_by", + function(table_handle, columns, ...) { + standardGeneric("first_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "first_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$first_by(columns))) + } +) + +setGeneric( + "last_by", + function(table_handle, columns, ...) { + standardGeneric("last_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "last_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$last_by(columns))) + } +) + +setGeneric( + "head_by", + function(table_handle, n, columns, ...) { + standardGeneric("head_by") + }, + signature = c("table_handle", "n", "columns") +) + +#' @export +setMethod( + "head_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, n, columns = character()) { + verify_positive_int("n", n, TRUE) + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$head_by(n, columns))) + } +) + +setGeneric( + "tail_by", + function(table_handle, n, columns, ...) { + standardGeneric("tail_by") + }, + signature = c("table_handle", "n", "columns") +) + +#' @export +setMethod( + "tail_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, n, columns = character()) { + verify_positive_int("n", n, TRUE) + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$tail_by(n, columns))) + } +) + +setGeneric( + "min_by", + function(table_handle, columns, ...) { + standardGeneric("min_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "min_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$min_by(columns))) + } +) + +setGeneric( + "max_by", + function(table_handle, columns, ...) { + standardGeneric("max_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "max_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$max_by(columns))) + } +) + +setGeneric( + "sum_by", + function(table_handle, columns, ...) { + standardGeneric("sum_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "sum_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sum_by(columns))) + } +) + +setGeneric( + "abs_sum_by", + function(table_handle, columns, ...) { + standardGeneric("abs_sum_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "abs_sum_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$abs_sum_by(columns))) + } +) + +setGeneric( + "avg_by", + function(table_handle, columns, ...) { + standardGeneric("avg_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "avg_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$avg_by(columns))) + } +) + +setGeneric( + "w_avg_by", + function(table_handle, weight_column, columns, ...) { + standardGeneric("w_avg_by") + }, + signature = c("table_handle", "weight_column", "columns") +) + +#' @export +setMethod( + "w_avg_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, weight_column, columns = character()) { + verify_string("weight_column", weight_column, TRUE) + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$w_avg_by(weight_column, columns))) + } +) + +setGeneric( + "median_by", + function(table_handle, columns, ...) { + standardGeneric("median_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "median_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$median_by(columns))) + } +) + +setGeneric( + "var_by", + function(table_handle, columns, ...) { + standardGeneric("var_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "var_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$var_by(columns))) + } +) + +setGeneric( + "std_by", + function(table_handle, columns, ...) { + standardGeneric("std_by") + }, + signature = c("table_handle", "columns") +) + +#' @export +setMethod( + "std_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns = character()) { + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$std_by(columns))) + } +) + +setGeneric( + "percentile_by", + function(table_handle, percentile, columns, ...) { + standardGeneric("percentile_by") + }, + signature = c("table_handle", "percentile", "columns") +) + +#' @export +setMethod( + "percentile_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, percentile, columns = character()) { + verify_in_unit_interval("percentile", percentile, TRUE) + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$percentile_by(percentile, columns))) + } +) + +setGeneric( + "count_by", + function(table_handle, count_by_column, columns, ...) { + standardGeneric("count_by") + }, + signature = c("table_handle", "count_by_column", "columns") +) + +#' @export +setMethod( + "count_by", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, count_by_column = "n", columns = character()) { + verify_string("count_by_column", count_by_column, TRUE) + verify_string("columns", columns, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$count_by(count_by_column, columns))) + } +) + +setGeneric( + "cross_join", + function(table_handle, right_side, columns_to_match, columns_to_add, ...) { + standardGeneric("cross_join") + }, + signature = c("table_handle", "right_side", "columns_to_match", "columns_to_add") +) + +#' @export +setMethod( + "cross_join", + signature = c(table_handle = "S4TableHandle", right_side = "S4TableHandle"), + function(table_handle, right_side, columns_to_match = character(), columns_to_add = character()) { + verify_string("columns_to_match", columns_to_match, FALSE) + verify_string("columns_to_add", columns_to_add, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$cross_join( + right_side@internal_table_handle, + columns_to_match, columns_to_add + ))) + } +) + +setGeneric( + "natural_join", + function(table_handle, right_side, columns_to_match, columns_to_add, ...) { + standardGeneric("natural_join") + }, + signature = c("table_handle", "right_side", "columns_to_match", "columns_to_add") +) + +#' @export +setMethod( + "natural_join", + signature = c(table_handle = "S4TableHandle", right_side = "S4TableHandle"), + function(table_handle, right_side, columns_to_match = character(), columns_to_add = character()) { + verify_string("columns_to_match", columns_to_match, FALSE) + verify_string("columns_to_add", columns_to_add, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$natural_join( + right_side@internal_table_handle, + columns_to_match, columns_to_add + ))) + } +) + +setGeneric( + "exact_join", + function(table_handle, right_side, columns_to_match, columns_to_add, ...) { + standardGeneric("exact_join") + }, + signature = c("table_handle", "right_side", "columns_to_match", "columns_to_add") +) + +#' @export +setMethod( + "exact_join", + signature = c(table_handle = "S4TableHandle", right_side = "S4TableHandle"), + function(table_handle, right_side, columns_to_match = character(), columns_to_add = character()) { + verify_string("columns_to_match", columns_to_match, FALSE) + verify_string("columns_to_add", columns_to_add, FALSE) + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$exact_join( + right_side@internal_table_handle, + columns_to_match, columns_to_add + ))) + } +) + +# Will not work yet! +#' @export +setGeneric( + "sort", + function(table_handle, columns, descending, ...) { + standardGeneric("sort") + }, + signature = c("table_handle", "columns", "descending") +) + +#' @export +setMethod( + "sort", + signature = c(table_handle = "S4TableHandle"), + function(table_handle, columns, descending = FALSE) { + verify_string("columns", columns, FALSE) + verify_bool("descending", descending, FALSE) + if ((length(descending) > 1) && length(descending) != length(columns)) { + stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) + } + return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(columns, descending))) + } +) + diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R deleted file mode 100644 index e99a645dc7c..00000000000 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ /dev/null @@ -1,149 +0,0 @@ -#' @title Deephaven TableHandles -#' @description Deephaven TableHandles are references to tables living on a Deephaven server. They provide an -#' interface for interacting with tables on the server. -#' -#' @usage NULL -#' @format NULL -#' @docType class -#' -#' @examples -#' -#' # connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication -#' client_options <- ClientOptions$new() -#' client <- Client$new(target = "localhost:10000", client_options = client_options) -#' -#' # open a table that already exists on the server -#' new_table_handle1 <- client$open_table("table_on_the_server") -#' -#' # convert the Deephaven table to an R data frame -#' new_data_frame <- new_table_handle1$to_data_frame() -#' -#' # modify new data frame in R -#' new_data_frame$New_Int_Col <- c(1, 2, 3, 4, 5) -#' new_data_frame$New_String_Col <- c("I", "am", "a", "string", "column") -#' -#' # push new data frame to the server and name it "new_table" -#' new_table_handle2 <- client$import_table(new_data_frame) -#' new_table_handle2$bind_to_variable("new_table") - -#' @export -TableHandle <- R6Class("TableHandle", - cloneable = FALSE, - public = list( - initialize = function(table_handle) { - if (first_class(table_handle) != "Rcpp_INTERNAL_TableHandle") { - stop("'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised.") - } - self$internal_table_handle <- table_handle - private$is_static_field <- self$internal_table_handle$is_static() - }, - - #' @description - #' Whether the table referenced by this TableHandle is static or not. - #' @return TRUE if the table is static, or FALSE if the table is ticking. - is_static = function() { - return(private$is_static_field) - }, - - #' @description - #' Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. - #' @return The number of rows in the table. - nrow = function() { - if (!private$is_static_field) { - stop("The number of rows is not yet supported for dynamic tables.") - } - return(self$internal_table_handle$num_rows()) - }, - - #' @description - #' Binds the table referenced by this TableHandle to a variable on the server, - #' enabling it to be accessed by that name from any Deephaven API. - #' @param name Name for this table on the server. - bind_to_variable = function(name) { - verify_string("name", name, TRUE) - self$internal_table_handle$bind_to_variable(name) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. - #' @return A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. - to_arrow_record_batch_stream_reader = function() { - ptr <- self$internal_table_handle$get_arrow_array_stream_ptr() - rbsr <- RecordBatchStreamReader$import_from_c(ptr) - return(rbsr) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an Arrow Table. - #' @return A Table containing the data from the table referenced by this TableHandle. - to_arrow_table = function() { - rbsr <- self$to_arrow_record_batch_stream_reader() - arrow_tbl <- rbsr$read_table() - return(arrow_tbl) - }, - - #' @description - #' Imports the table referenced by this TableHandle into a dplyr Tibble. - #' @return A Tibble containing the data from the table referenced by this TableHandle. - to_tibble = function() { - rbsr <- self$to_arrow_record_batch_stream_reader() - arrow_tbl <- rbsr$read_table() - return(as_tibble(arrow_tbl)) - }, - - #' @description - #' Imports the table referenced by this TableHandle into an R Data Frame. - #' @return A Data Frame containing the data from the table referenced by this TableHandle. - to_data_frame = function() { - arrow_tbl <- self$to_arrow_table() - return(as.data.frame(as.data.frame(arrow_tbl))) # TODO: for some reason as.data.frame on arrow table returns a tibble, not a data frame - }, - internal_table_handle = NULL - ), - private = list( - is_static_field = NULL - ) -) - -# EXISTING GENERICS THAT WE CAN SUPPORT - -#' @export -print.TableHandle <- function(th, ...) { - cat("A Deephaven TableHandle:\n") - print(th$to_data_frame()) -} - -#' @export -as_arrow_table.TableHandle <- function(th, ...) { - th$to_arrow_table() -} - -#' @export -as_tibble.TableHandle <- function(th, ...) { - th$to_tibble() -} - -#' @export -as.data.frame.TableHandle <- function(th, ...) { - th$to_data_frame() -} - -#' @export -head.TableHandle <- function(th, n) { - verify_positive_int("n", n, TRUE) - return(TableHandle$new(th$internal_table_handle$head(n))) -} - -#' @export -tail.TableHandle <- function(th, n) { - verify_positive_int("n", n, TRUE) - return(TableHandle$new(th$internal_table_handle$tail(n))) -} - -#' @export -rbind.TableHandle <- function(th, sources) { - verify_type("sources", sources, "TableHandle", "Deephaven TableHandle", FALSE) - sources <- c(sources) - unwrapped_sources <- lapply(sources, strip_r6_wrapping_from_table_handle) - return(TableHandle$new(th$internal_table_handle$merge(unwrapped_sources))) -} diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R deleted file mode 100644 index d16d926a414..00000000000 --- a/R/rdeephaven/R/table_ops.R +++ /dev/null @@ -1,321 +0,0 @@ -#' @name TableOps -#' @title Deephaven TableHandle operations -#' @description These TableHandle operations provide a dplyr-like interface for filtering, aggregating, and summarizing -#' data in Deephaven Tables living on the server. For large datasets, constructing queries with these operations before -#' pulling results into an R data frame will be more performant than first pulling a Deephaven Table into an R data frame -#' and using existing dplyr methods. Additionally, these operations seamlessly support real-time Deephaven Tables, and -#' the resulting downstream tables will be automatically updated on the server when the parent tables update. -NULL - -# FILTERING OPERATIONS - -#' @description -#' Creates a new in-memory table that includes one column for each argument. -#' @param by A string or list of strings specifying the columns to view. -#' @export -select <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - TableHandle$new(th$internal_table_handle$select(columns)) -} - -#' @description -#' Creates a new formula table that includes one column for each argument. -#' @param by A string or list of strings specifying the columns to view. -#' @return TableHandle reference to the new table. -#' @export -view <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$view(columns))) -} - -#' @description -#' Creates a new table containing a new in-memory column for each argument. -#' @param by A string or list of strings specifying the formulas to create new columns. -#' @return TableHandle reference to the new table. -#' @export -update <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$update(columns))) -} - -#' @description -#' Creates a new formula table containing a new formula for each argument. -#' @param by A string or list of strings specifying the formulas to create new columns. -#' @return TableHandle reference to the new table. -#' @export -update_view <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$update_view(columns))) -} - -#' @description -#' Creates a new table with the same size as this table, but omits any of the specified columns. -#' @param by A string or list of strings specifying the column names to drop. -#' @return TableHandle reference to the new table. -#' @export -drop_columns <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$drop_columns(columns))) -} - -#' @description -#' Creates a new table only containing the rows that meet the specified condition. -#' @param condition A string specifying a conditional expression. -#' @return TableHandle reference to the new table. -#' @export -where <- function(th, condition) { - verify_string("condition", condition, TRUE) - return(TableHandle$new(th$internal_table_handle$where(condition))) -} - -# AGGREGATION OPERATIONS - -#' @description -#' Creates a new table containing grouping columns and grouped data, with column content grouped into arrays. -#' @param group_by_columns A string or list of strings specifying the columns to group by. -#' @return TableHandle reference to the new table. -#' @export -group_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$group_by(columns))) -} - -#' @description -#' Creates a new table in which array columns from the source table are unwrapped into separate rows. -#' This is the inverse of a `group_by()` aggregation. -#' @param group_by_columns A string or list of strings specifying the columns to ungroup by. -#' @return TableHandle reference to the new table. -#' @export -ungroup <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$ungroup(columns))) -} - -#' @description -#' Creates a new table containing grouping columns and grouped data, defined by the specified aggregation(s). -#' @param aggregations A Deephaven Aggregation or a list of Aggregations specifying the aggregations to perform on the data. -#' TODO: Link agg_* docs for more info -#' @param group_by_columns #' @param group_by_columns A string or list of strings specifying the columns to group by. -#' @return TableHandle reference to the new table. -#' @export -agg_by <- function(th, aggregations, columns = character()) { - verify_type("aggregations", aggregations, "Aggregation", "Deephaven Aggregation", FALSE) - verify_string("columns", columns, FALSE) - aggregations <- c(aggregations) - unwrapped_aggregations <- lapply(aggregations, strip_r6_wrapping_from_aggregation) - return(TableHandle$new(th$internal_table_handle$agg_by(unwrapped_aggregations, columns))) -} - -#' @description -#' Creates a new table which contains the first row of each distinct group. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -first_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$first_by(columns))) -} - -#' @description -#' Creates a new table which contains the last row of each distinct group. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -last_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$last_by(columns))) -} - -#' @description -#' Creates a new table which contains the first n rows of each distinct group. -#' @param n An integer specifying the number of rows to include for each group. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -head_by <- function(th, n, columns = character()) { - verify_positive_int("n", n, TRUE) - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$head_by(n, columns))) -} - -#' @description -#' Creates a new table which contains the last n rows of each distinct group. -#' @param n An integer specifying the number of rows to include for each group. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -tail_by <- function(th, n, columns = character()) { - verify_positive_int("n", n, TRUE) - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$tail_by(n, columns))) -} - -#' @description -#' Creates a new table which contains the columnwise minimum of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -min_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$min_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise maximum of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -max_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$max_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise sum of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -sum_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$sum_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise sum of absolute values of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -abs_sum_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$abs_sum_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise average of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -avg_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$avg_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise weighted average of each distinct group, only defined for numeric columns. -#' @param weight_column A numeric column to use for the weights. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -w_avg_by <- function(th, weight_column, columns = character()) { - verify_string("weight_column", weight_column, TRUE) - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$w_avg_by(weight_column, columns))) -} - -#' @description -#' Creates a new table which contains the columnwise median of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -median_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$median_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise variance of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -var_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$var_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise standard deviation of each distinct group, only defined for numeric columns. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -std_by <- function(th, columns = character()) { - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$std_by(columns))) -} - -#' @description -#' Creates a new table which contains the columnwise pth percentile of each distinct group, only defined for numeric columns. -#' @param percentile A float in [0, 1] specifying the percentile. The results will be the values in the source table -#' nearest to the pth percentile, and no interpolation or estimation will be performed. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -percentile_by <- function(th, percentile, columns = character()) { - verify_in_unit_interval("percentile", percentile, TRUE) - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$percentile_by(percentile, columns))) -} - -#' @description -#' Creates a new table which contains the number of rows in each distinct group. -#' @param count_by_column A string specifying the name of the new count column. -#' @param by A string or list of strings specifying the column names to group by. -#' @return TableHandle reference to the new table. -#' @export -count_by <- function(th, count_by_column = "n", columns = character()) { - verify_string("count_by_column", count_by_column, TRUE) - verify_string("columns", columns, FALSE) - return(TableHandle$new(th$internal_table_handle$count_by(count_by_column, columns))) -} - -# JOIN OPERATIONS - -# TODO: Figure out the right defaults here to make interpretation simple -#' @export -cross_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string("columns_to_match", columns_to_match, FALSE) - verify_string("columns_to_add", columns_to_add, FALSE) - return(TableHandle$new(th$internal_table_handle$cross_join( - right_side$internal_table_handle, - columns_to_match, columns_to_add - ))) -} - -# TODO: Document this well -#' @export -natural_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string("columns_to_match", columns_to_match, FALSE) - verify_string("columns_to_add", columns_to_add, FALSE) - return(TableHandle$new(th$internal_table_handle$natural_join( - right_side$internal_table_handle, - columns_to_match, columns_to_add - ))) -} - -# TODO: Document this well -#' @export -exact_join <- function(th, right_side, columns_to_match, columns_to_add) { - verify_string("columns_to_match", columns_to_match, FALSE) - verify_string("columns_to_add", columns_to_add, FALSE) - return(TableHandle$new(th$internal_table_handle$exact_join( - right_side$internal_table_handle, - columns_to_match, columns_to_add - ))) -} - -# MISC OPERATIONS - -#' @description -#' Creates a new table with rows sorted by the values in each distinct group. -#' @param by A string or list of strings specifying the column names to group by. -#' @param descending A boolean or list of booleans the same size as columns, specifying -#' whether the sort should be descending or not. Defaults to ascending sort. -#' @return TableHandle reference to the new table. -#' @export -sort <- function(th, columns, descending = FALSE) { - verify_string("columns", columns, FALSE) - verify_bool("descending", descending, FALSE) - if ((length(descending) > 1) && length(descending) != length(columns)) { - stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) - } - return(TableHandle$new(th$internal_table_handle$sort(columns, descending))) -} diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 402633a3eeb..bcbfd3182ed 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -1,5 +1,6 @@ -library(testthat) +library(dplyr) library(rdeephaven) +library(testthat) setup <- function() { df1 <- data.frame( @@ -38,19 +39,18 @@ setup <- function() { # in order to test TableHandle, we need to have tables on the server that we know everything about. # thus, we have to push these created tables to the server and get TableHandles to each of them. - # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() # set up client - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client_options <- new("S4ClientOptions") + client <- connect(target = "localhost:10000", client_options = client_options) # move dataframes to server and get TableHandles for testing - th1 <- client$import_table(df1) - th2 <- client$import_table(df2) - th3 <- client$import_table(df3) - th4 <- client$import_table(df4) - th5 <- client$import_table(df5) - th6 <- client$import_table(df6) + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) + th5 <- import_table(client, df5) + th6 <- import_table(client, df6) return(list( "client" = client, @@ -97,7 +97,7 @@ test_that("select behaves as expected", { select(c("X", "Number3 = Number1 * Number2")) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - data$client$close() + close(data$client) }) test_that("view behaves as expected", { @@ -136,7 +136,7 @@ test_that("view behaves as expected", { view(c("X", "Number3 = Number1 * Number2")) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - data$client$close() + close(data$client) }) test_that("update behaves as expected", { @@ -172,7 +172,7 @@ test_that("update behaves as expected", { update("Number3 = Number1 + Number2") expect_equal(as.data.frame(new_tb5), as.data.frame(new_th5)) - data$client$close() + close(data$client) }) test_that("update_view behaves as expected", { @@ -208,7 +208,7 @@ test_that("update_view behaves as expected", { update_view("Number3 = Number1 + Number2") expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - data$client$close() + close(data$client) }) test_that("drop_columns behaves as expected", { @@ -232,7 +232,7 @@ test_that("drop_columns behaves as expected", { drop_columns(paste0("X", seq(2, 1000))) expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - data$client$close() + close(data$client) }) test_that("where behaves as expected", { @@ -256,7 +256,7 @@ test_that("where behaves as expected", { where("X1 - X4 + X8 + X32 - 2*X5 >= 0") expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - data$client$close() + close(data$client) }) test_that("group_by and ungroup behaves as expected", { @@ -290,7 +290,7 @@ test_that("group_by and ungroup behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(data$th6 %>% sort(c("X", "Y")))) - data$client$close() + close(data$client) }) test_that("first_by behaves as expected", { @@ -314,7 +314,7 @@ test_that("first_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("last_by behaves as expected", { @@ -338,7 +338,7 @@ test_that("last_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("head_by behaves as expected", { @@ -359,7 +359,7 @@ test_that("head_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("tail_by behaves as expected", { @@ -380,7 +380,7 @@ test_that("tail_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("min_by behaves as expected", { @@ -420,7 +420,7 @@ test_that("min_by behaves as expected", { sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - data$client$close() + close(data$client) }) test_that("max_by behaves as expected", { @@ -460,7 +460,7 @@ test_that("max_by behaves as expected", { sort("bool_col") expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - data$client$close() + close(data$client) }) test_that("sum_by behaves as expected", { @@ -484,7 +484,7 @@ test_that("sum_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("abs_sum_by behaves as expected", { @@ -510,7 +510,7 @@ test_that("abs_sum_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("avg_by behaves as expected", { @@ -534,7 +534,7 @@ test_that("avg_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("w_avg_by behaves as expected", { @@ -568,7 +568,7 @@ test_that("w_avg_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("median_by behaves as expected", { @@ -592,7 +592,7 @@ test_that("median_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("var_by behaves as expected", { @@ -616,7 +616,7 @@ test_that("var_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("std_by behaves as expected", { @@ -640,7 +640,7 @@ test_that("std_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("percentile_by behaves as expected", { @@ -670,7 +670,7 @@ test_that("percentile_by behaves as expected", { expect_equal(as.data.frame(new_th2), new_df2) - data$client$close() + close(data$client) }) test_that("count_by behaves as expected", { @@ -689,7 +689,7 @@ test_that("count_by behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - data$client$close() + close(data$client) }) test_that("sort behaves as expected", { @@ -725,7 +725,7 @@ test_that("sort behaves as expected", { sort(c("X", "Y", "Number1"), descending = c(FALSE, TRUE, FALSE)) expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - data$client$close() + close(data$client) }) test_that("cross_join behaves as expected", { @@ -744,7 +744,7 @@ test_that("cross_join behaves as expected", { ) expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - data$client$close() + close(data$client) }) test_that("natural_join behaves as expected", { @@ -771,7 +771,7 @@ test_that("natural_join behaves as expected", { ) expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - data$client$close() + close(data$client) }) # TODO: Verify that inner_join is the analog of exact_join @@ -796,5 +796,5 @@ test_that("exact_join behaves as expected", { rename(Number1 = Number1.x, Number2 = Number2.x, Number3 = Number1.y, Number4 = Number2.y) expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - data$client$close() + close(data$client) }) diff --git a/R/rdeephaven/man/Client.Rd b/R/rdeephaven/man/Client.Rd deleted file mode 100644 index d39feec15c7..00000000000 --- a/R/rdeephaven/man/Client.Rd +++ /dev/null @@ -1,161 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/client_wrapper.R -\docType{class} -\name{Client} -\alias{Client} -\title{The Deephaven Client} -\description{ -The Deephaven Client class is responsible for establishing and maintaining -a connection to a running Deephaven server and facilitating basic server requests. -} -\examples{ - -# connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication -client_options <- ClientOptions$new() -client <- Client$new(target="localhost:10000", client_options=client_options) - -# open a table that already exists on the server -new_table_handle1 <- client$open_table("table_on_the_server") - -# create a new dataframe, import onto the server, and retrieve a reference -new_data_frame <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) -new_table_handle2 <- client$import_table(new_data_frame) - -# run a python script on the server (default client options specify a Python console) -client$run_script("print([i for i in range(10)])") -} -\section{Methods}{ -\subsection{Public methods}{ -\itemize{ -\item \href{#method-Client-new}{\code{Client$new()}} -\item \href{#method-Client-open_table}{\code{Client$open_table()}} -\item \href{#method-Client-empty_table}{\code{Client$empty_table()}} -\item \href{#method-Client-time_table}{\code{Client$time_table()}} -\item \href{#method-Client-import_table}{\code{Client$import_table()}} -\item \href{#method-Client-run_script}{\code{Client$run_script()}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Client-new}{}}} -\subsection{Method \code{new()}}{ -Connect to a running Deephaven server. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Client$new(target, client_options)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{target}}{The address of the Deephaven server.} - -\item{\code{client_options}}{ClientOptions instance with the parameters needed to connect to the server. -See ?ClientOptions for more information.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Client-open_table}{}}} -\subsection{Method \code{open_table()}}{ -Opens a table named 'name' from the server if it exists. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Client$open_table(name)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{name}}{Name of the table to open from the server, passed as a string.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -TableHandle reference to the requested table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Client-empty_table}{}}} -\subsection{Method \code{empty_table()}}{ -Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Client$empty_table(size)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{size}}{Number of rows in the empty table.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -TableHandle reference to the new table, which has not yet been named on the server. - See TableHandle$bind_to_variable() for naming a new table on the server. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Client-time_table}{}}} -\subsection{Method \code{time_table()}}{ -Creates a ticking table. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Client$time_table(start_time_nanos, period_nanos)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{start_time_nanos}}{When the table should start ticking (in units of nanoseconds since the epoch).} - -\item{\code{period_nanos}}{Table ticking frequency (in nanoseconds).} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -TableHandle reference to the new table, which has not yet been named on the server. - See TableHandle$bind_to_variable() for naming a new table on the server. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Client-import_table}{}}} -\subsection{Method \code{import_table()}}{ -Imports a new table to the Deephaven server. Note that this new table is not automatically bound to -a variable name on the server. See `?TableHandle` for more information. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Client$import_table(table_object)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{table_object}}{An R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow RecordBatchReader -containing the data to import to the server.} -} -\if{html}{\out{
}} -} -\subsection{Returns}{ -TableHandle reference to the new table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Client-run_script}{}}} -\subsection{Method \code{run_script()}}{ -Runs a script on the server. The script must be in the language that the server console was started with. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Client$run_script(script)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{script}}{Code to be executed on the server, passed as a string.} -} -\if{html}{\out{
}} -} -} -} diff --git a/R/rdeephaven/man/ClientOptions.Rd b/R/rdeephaven/man/ClientOptions.Rd deleted file mode 100644 index f7e00204ddf..00000000000 --- a/R/rdeephaven/man/ClientOptions.Rd +++ /dev/null @@ -1,200 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/client_options_wrapper.R -\docType{class} -\name{ClientOptions} -\alias{ClientOptions} -\title{Deephaven ClientOptions} -\description{ -Client options provide a simple interface to the Deephaven server's authentication protocols. -This makes it easy to connect to a Deephaven server with any flavor of authentication, and shields the API from -any future changes to the underlying implementation. - -Currently, three different kinds of authentication that a Deephaven server might be using are suported: - -- "default": Default (or anonymous) authentication does not require any username or password. If - running the Deephaven server locally, this is probably the kind of authentication needed. - -- "basic": Basic authentication requires a standard username and password pair. - -- "custom": Custom authentication requires general key-value pairs. - -In addition to setting the authentication parameters when connecting to a client, a console can be -started in one of our supported server languages. Python and Groovy are currently supported, and the -user must ensure that the server being connected to was started with support for the desired console language. -} -\examples{ - -# connect to a Deephaven server with a Python console running on "localhost:10000" using anonymous 'default' authentication -client_options <- ClientOptions$new() -client <- Client$new(target="localhost:10000", client_options=client_options) - -# connect to a secure Deephaven server with a Groovy console using username/password authentication -client_options <- ClientOptions$new() -client_options$set_basic_authentication(username="user", password="p@ssw0rd123") -client_options$set_session_type("groovy") -client <- Client$new(target="url/to/secure/server", client_options=client_options) -} -\section{Methods}{ -\subsection{Public methods}{ -\itemize{ -\item \href{#method-ClientOptions-new}{\code{ClientOptions$new()}} -\item \href{#method-ClientOptions-set_default_authentication}{\code{ClientOptions$set_default_authentication()}} -\item \href{#method-ClientOptions-set_basic_authentication}{\code{ClientOptions$set_basic_authentication()}} -\item \href{#method-ClientOptions-set_custom_authentication}{\code{ClientOptions$set_custom_authentication()}} -\item \href{#method-ClientOptions-set_session_type}{\code{ClientOptions$set_session_type()}} -\item \href{#method-ClientOptions-use_tls}{\code{ClientOptions$use_tls()}} -\item \href{#method-ClientOptions-add_int_option}{\code{ClientOptions$add_int_option()}} -\item \href{#method-ClientOptions-add_string_option}{\code{ClientOptions$add_string_option()}} -\item \href{#method-ClientOptions-add_extra_header}{\code{ClientOptions$add_extra_header()}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-new}{}}} -\subsection{Method \code{new()}}{ -Create a ClientOptions instance. This will default to using default (anonymous) authentication and a Python console. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$new()}\if{html}{\out{
}} -} - -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-set_default_authentication}{}}} -\subsection{Method \code{set_default_authentication()}}{ -Use default (anonymous) authentication. If running a Deephaven server locally, this is likely the kind of authentication needed. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$set_default_authentication()}\if{html}{\out{
}} -} - -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-set_basic_authentication}{}}} -\subsection{Method \code{set_basic_authentication()}}{ -Use basic (username/password based) authentication. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$set_basic_authentication(username, password)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{username}}{Username of the account to use for authentication, supplied as a string.} - -\item{\code{password}}{Password of the account, supplied as a string.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-set_custom_authentication}{}}} -\subsection{Method \code{set_custom_authentication()}}{ -Use custom (general key/value based) authentication. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$set_custom_authentication(auth_key, auth_value)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{auth_key}}{Key to use for authentication, supplied as a string.} - -\item{\code{auth_value}}{Value to use for authentication, supplied as a string.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-set_session_type}{}}} -\subsection{Method \code{set_session_type()}}{ -Set the session type of the console (e.g., "python", "groovy", etc.). The session type must be supported on the server. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$set_session_type(session_type)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{session_type}}{Desired language of the console. "python", "groovy", etc.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-use_tls}{}}} -\subsection{Method \code{use_tls()}}{ -Use the TLS protocol in authentication and subsequent communication. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$use_tls(root_certs = "")}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{root_certs}}{Optional PEM-encoded certificate root for server connections. Defaults to system defaults. -Adds an int-valued option for the configuration of the underlying gRPC channels.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-add_int_option}{}}} -\subsection{Method \code{add_int_option()}}{ -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$add_int_option(opt, val)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{opt}}{The option key.} - -\item{\code{val}}{The option value.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-add_string_option}{}}} -\subsection{Method \code{add_string_option()}}{ -Adds a string-valued option for the configuration of the underlying gRPC channels. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$add_string_option(opt, val)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{opt}}{The option key.} - -\item{\code{val}}{The option valiue.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-ClientOptions-add_extra_header}{}}} -\subsection{Method \code{add_extra_header()}}{ -Adds an extra header with a constant name and value to be sent with every outgoing server request. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{ClientOptions$add_extra_header(header_name, header_value)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{header_name}}{The header name} - -\item{\code{header_value}}{The header value} -} -\if{html}{\out{
}} -} -} -} diff --git a/R/rdeephaven/man/TableHandle.Rd b/R/rdeephaven/man/TableHandle.Rd deleted file mode 100644 index 888b6b8e182..00000000000 --- a/R/rdeephaven/man/TableHandle.Rd +++ /dev/null @@ -1,149 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/table_handle_wrapper.R -\docType{class} -\name{TableHandle} -\alias{TableHandle} -\title{Deephaven TableHandles} -\description{ -Deephaven TableHandles are references to tables living on a Deephaven server. They provide an -interface for interacting with tables on the server. -} -\examples{ - -# connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication -client_options <- ClientOptions$new() -client <- Client$new(target="localhost:10000", client_options=client_options) - -# open a table that already exists on the server -new_table_handle1 <- client$open_table("table_on_the_server") - -# convert the Deephaven table to an R data frame -new_data_frame <- new_table_handle1$to_data_frame() - -# modify new data frame in R -new_data_frame$New_Int_Col <- c(1, 2, 3, 4, 5) -new_data_frame$New_String_Col <- c("I", "am", "a", "string", "column") - -# push new data frame to the server and name it "new_table" -new_table_handle2 <- client$import_table(new_data_frame) -new_table_handle2$bind_to_variable("new_table") -} -\section{Methods}{ -\subsection{Public methods}{ -\itemize{ -\item \href{#method-TableHandle-new}{\code{TableHandle$new()}} -\item \href{#method-TableHandle-is_static}{\code{TableHandle$is_static()}} -\item \href{#method-TableHandle-nrow}{\code{TableHandle$nrow()}} -\item \href{#method-TableHandle-bind_to_variable}{\code{TableHandle$bind_to_variable()}} -\item \href{#method-TableHandle-to_arrow_record_batch_stream_reader}{\code{TableHandle$to_arrow_record_batch_stream_reader()}} -\item \href{#method-TableHandle-to_arrow_table}{\code{TableHandle$to_arrow_table()}} -\item \href{#method-TableHandle-to_tibble}{\code{TableHandle$to_tibble()}} -\item \href{#method-TableHandle-to_data_frame}{\code{TableHandle$to_data_frame()}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-new}{}}} -\subsection{Method \code{new()}}{ -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$new(table_handle)}\if{html}{\out{
}} -} - -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-is_static}{}}} -\subsection{Method \code{is_static()}}{ -Whether the table referenced by this TableHandle is static or not. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$is_static()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -TRUE if the table is static, or FALSE if the table is ticking. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-nrow}{}}} -\subsection{Method \code{nrow()}}{ -Number of rows in the table referenced by this TableHandle, currently only implemented for static tables. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$nrow()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -The number of rows in the table. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-bind_to_variable}{}}} -\subsection{Method \code{bind_to_variable()}}{ -Binds the table referenced by this TableHandle to a variable on the server, -enabling it to be accessed by that name from any Deephaven API. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$bind_to_variable(name)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{name}}{Name for this table on the server.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_arrow_record_batch_stream_reader}{}}} -\subsection{Method \code{to_arrow_record_batch_stream_reader()}}{ -Imports the table referenced by this TableHandle into an Arrow RecordBatchStreamReader. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_arrow_record_batch_stream_reader()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A RecordBatchStreamReader containing the data from the table referenced by this TableHandle. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_arrow_table}{}}} -\subsection{Method \code{to_arrow_table()}}{ -Imports the table referenced by this TableHandle into an Arrow Table. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_arrow_table()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A Table containing the data from the table referenced by this TableHandle. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_tibble}{}}} -\subsection{Method \code{to_tibble()}}{ -Imports the table referenced by this TableHandle into a dplyr Tibble. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_tibble()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A Tibble containing the data from the table referenced by this TableHandle. -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TableHandle-to_data_frame}{}}} -\subsection{Method \code{to_data_frame()}}{ -Imports the table referenced by this TableHandle into an R Data Frame. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{TableHandle$to_data_frame()}\if{html}{\out{
}} -} - -\subsection{Returns}{ -A Data Frame containing the data from the table referenced by this TableHandle. -} -} -} From 8033299122afab1198ec4c101a9924c1eefac5f5 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 4 Aug 2023 17:22:35 -0500 Subject: [PATCH 43/73] Working unit tests, refactor complete --- R/rdeephaven/DESCRIPTION | 4 +- R/rdeephaven/NAMESPACE | 48 ++-- R/rdeephaven/R/exports.R | 4 + R/rdeephaven/R/new_aggregate_wrapper.R | 54 ++--- R/rdeephaven/R/new_client_options_wrapper.R | 168 ------------- R/rdeephaven/R/new_client_wrapper.R | 127 ++++++++-- R/rdeephaven/R/new_table_handle_wrapper.R | 50 ++-- R/rdeephaven/R/new_table_ops.R | 168 +++++++------ .../inst/tests/testthat/test_agg_by.R | 42 ++-- .../tests/testthat/test_aggregate_wrapper.R | 7 - .../testthat/test_client_options_wrapper.R | 163 ------------- .../inst/tests/testthat/test_client_wrapper.R | 220 +++++++----------- .../testthat/test_table_handle_wrapper.R | 113 +++++---- .../inst/tests/testthat/test_table_ops.R | 5 +- 14 files changed, 430 insertions(+), 743 deletions(-) delete mode 100644 R/rdeephaven/R/new_client_options_wrapper.R delete mode 100644 R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R diff --git a/R/rdeephaven/DESCRIPTION b/R/rdeephaven/DESCRIPTION index 21bbf3bcd7b..ed89c74e251 100644 --- a/R/rdeephaven/DESCRIPTION +++ b/R/rdeephaven/DESCRIPTION @@ -13,8 +13,8 @@ Description: The `rdeephaven` package provides an R API for communicating with t and bind it to a server-side variable so you can access it from any Deephaven client. Finally, you can run Python or Groovy scripts on the Deephaven server, so long as your server is equipped with that capability. License: Apache License (== 2.0) -Depends: R (> 4.1.2), Rcpp (>= 1.0.10), arrow (>= 12.0.0), magrittr (>= 2.0.0) -Imports: Rcpp (>= 1.0.10), arrow (>= 12.0.0), magrittr (>= 2.0.0) +Depends: R (> 4.1.2), Rcpp (>= 1.0.10), arrow (>= 12.0.0), dplyr (>= 1.1.0) +Imports: Rcpp (>= 1.0.10), arrow (>= 12.0.0), R6 (>= 2.5.0), dplyr (>= 1.1.0) LinkingTo: Rcpp Suggests: testthat (>= 3.0.0) Config/testthat/edition: 3 diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 65ca67503d6..a275eb55fbb 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -1,31 +1,27 @@ # Generated by roxygen2: do not edit by hand -export(s4_agg_abs_sum) -export(s4_agg_avg) -export(s4_agg_count) -export(s4_agg_first) -export(s4_agg_last) -export(s4_agg_max) -export(s4_agg_median) -export(s4_agg_min) -export(s4_agg_percentile) -export(s4_agg_std) -export(s4_agg_sum) -export(s4_agg_var) -export(s4_agg_w_avg) +export(agg_abs_sum) +export(agg_avg) +export(agg_count) +export(agg_first) +export(agg_last) +export(agg_max) +export(agg_median) +export(agg_min) +export(agg_percentile) +export(agg_std) +export(agg_sum) +export(agg_var) +export(agg_w_avg) export(sort) -exportClasses(S4Aggregation) -exportClasses(S4Client) -exportClasses(S4ClientOptions) -exportClasses(S4TableHandle) +exportClasses(Aggregation) +exportClasses(Client) +exportClasses(TableHandle) exportMethods(abs_sum_by) -exportMethods(add_extra_header) -exportMethods(add_int_option) -exportMethods(add_string_option) exportMethods(agg_by) exportMethods(as.data.frame) -exportMethods(as_arrow_record_batch_stream_reader) exportMethods(as_arrow_table) +exportMethods(as_record_batch_reader) exportMethods(as_tibble) exportMethods(avg_by) exportMethods(bind_to_variable) @@ -41,21 +37,17 @@ exportMethods(group_by) exportMethods(head) exportMethods(head_by) exportMethods(import_table) -exportMethods(initialize) exportMethods(is_static) exportMethods(last_by) exportMethods(max_by) exportMethods(median_by) exportMethods(min_by) exportMethods(natural_join) +exportMethods(nrow) exportMethods(open_table) exportMethods(percentile_by) exportMethods(run_script) exportMethods(select) -exportMethods(set_basic_authentication) -exportMethods(set_custom_authentication) -exportMethods(set_default_authentication) -exportMethods(set_session_type) exportMethods(sort) exportMethods(std_by) exportMethods(sum_by) @@ -65,7 +57,6 @@ exportMethods(time_table) exportMethods(ungroup) exportMethods(update) exportMethods(update_view) -exportMethods(use_tls) exportMethods(var_by) exportMethods(view) exportMethods(w_avg_by) @@ -73,6 +64,9 @@ exportMethods(where) import(Rcpp) importFrom(Rcpp,evalCpp) importFrom(arrow,RecordBatchStreamReader) +importFrom(arrow,arrow_table) importFrom(arrow,as_arrow_table) +importFrom(arrow,as_record_batch_reader) importFrom(dplyr,as_tibble) +importFrom(magrittr,"%>%") useDynLib(rdeephaven, .registration = TRUE) diff --git a/R/rdeephaven/R/exports.R b/R/rdeephaven/R/exports.R index 0c34ac82bc4..3573cf37784 100644 --- a/R/rdeephaven/R/exports.R +++ b/R/rdeephaven/R/exports.R @@ -1,5 +1,9 @@ #' @import Rcpp #' @useDynLib rdeephaven, .registration = TRUE #' @importFrom Rcpp evalCpp +#' +#' @importFrom magrittr %>% +#' @importFrom arrow arrow_table as_arrow_table as_record_batch_reader RecordBatchStreamReader +#' @importFrom dplyr as_tibble loadModule("DeephavenInternalModule", TRUE) diff --git a/R/rdeephaven/R/new_aggregate_wrapper.R b/R/rdeephaven/R/new_aggregate_wrapper.R index 51863c99f76..3270cad84b3 100644 --- a/R/rdeephaven/R/new_aggregate_wrapper.R +++ b/R/rdeephaven/R/new_aggregate_wrapper.R @@ -1,6 +1,6 @@ #' @export setClass( - "S4Aggregation", + "Aggregation", representation( .internal_rcpp_object = "Rcpp_INTERNAL_Aggregate" ) @@ -9,81 +9,81 @@ setClass( ### All of the functions below return an instance of the above class #' @export -s4_agg_first <- function(columns = character()) { +agg_first <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_first(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_first(columns))) } #' @export -s4_agg_last <- function(columns = character()) { +agg_last <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_last(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_last(columns))) } #' @export -s4_agg_min <- function(columns = character()) { +agg_min <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_min(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_min(columns))) } #' @export -s4_agg_max <- function(columns = character()) { +agg_max <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_max(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_max(columns))) } #' @export -s4_agg_sum <- function(columns = character()) { +agg_sum <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_sum(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_sum(columns))) } #' @export -s4_agg_abs_sum <- function(columns = character()) { +agg_abs_sum <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_abs_sum(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_abs_sum(columns))) } #' @export -s4_agg_avg <- function(columns = character()) { +agg_avg <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_avg(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_avg(columns))) } #' @export -s4_agg_w_avg <- function(weight_column, columns = character()) { +agg_w_avg <- function(weight_column, columns = character()) { verify_string("weight_column", weight_column, TRUE) verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_w_avg(weight_column, columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_w_avg(weight_column, columns))) } #' @export -s4_agg_median <- function(columns = character()) { +agg_median <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_median(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_median(columns))) } #' @export -s4_agg_var <- function(columns = character()) { +agg_var <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_var(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_var(columns))) } #' @export -s4_agg_std <- function(columns = character()) { +agg_std <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_std(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_std(columns))) } #' @export -s4_agg_percentile <- function(percentile, columns = character()) { +agg_percentile <- function(percentile, columns = character()) { verify_in_unit_interval("percentile", percentile, TRUE) verify_string("columns", columns, FALSE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_percentile(percentile, columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_percentile(percentile, columns))) } #' @export -s4_agg_count <- function(count_column) { +agg_count <- function(count_column) { verify_string("count_column", count_column, TRUE) - return(new("S4Aggregation", .internal_rcpp_object = INTERNAL_count(count_column))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_count(count_column))) } \ No newline at end of file diff --git a/R/rdeephaven/R/new_client_options_wrapper.R b/R/rdeephaven/R/new_client_options_wrapper.R deleted file mode 100644 index 7c3f832d887..00000000000 --- a/R/rdeephaven/R/new_client_options_wrapper.R +++ /dev/null @@ -1,168 +0,0 @@ -#' @export -setClass( - "S4ClientOptions", - representation( - .internal_rcpp_object = "Rcpp_INTERNAL_ClientOptions" - ) -) - -#' @export -setMethod( - "initialize", "S4ClientOptions", - function(.Object) { - internal_client_options <- new(INTERNAL_ClientOptions) - .Object <- callNextMethod(.Object, - .internal_rcpp_object = internal_client_options) - return(.Object) - } -) - -# ALL OF THE FOLLOWING METHODS ARE CURRENTLY ONLY CALLED FOR THEIR SIDE-EFFECTS - -setGeneric( - "set_default_authentication", - function(client_options_instance) { - return(standardGeneric("set_default_authentication")) - }, - signature = c("client_options_instance") -) - -#' @export -setMethod( - "set_default_authentication", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance) { - return(client_options_instance@.internal_rcpp_object$set_default_authentication()) - } -) - -setGeneric( - "set_basic_authentication", - function(client_options_instance, username, password) { - return(standardGeneric("set_basic_authentication")) - }, - signature = c("client_options_instance", "username", "password") -) - -#' @export -setMethod( - "set_basic_authentication", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, username, password) { - verify_string("username", username, TRUE) - verify_string("password", password, TRUE) - return(client_options_instance@.internal_rcpp_object$set_basic_authentication(username, password)) - } -) - -setGeneric( - "set_custom_authentication", - function(client_options_instance, auth_key, auth_value) { - return(standardGeneric("set_custom_authentication")) - }, - signature = c("client_options_instance", "auth_key", "auth_value") -) - -#' @export -setMethod( - "set_custom_authentication", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, auth_key, auth_value) { - verify_string("auth_key", auth_key, TRUE) - verify_string("auth_value", auth_value, TRUE) - return(client_options_instance@.internal_rcpp_object$set_custom_authentication(auth_key, auth_value)) - } -) - -setGeneric( - "set_session_type", - function(client_options_instance, session_type) { - return(standardGeneric("set_session_type")) - }, - signature = c("client_options_instance", "session_type") -) - -#' @export -setMethod( - "set_session_type", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, session_type) { - verify_string("session_type", session_type, TRUE) - return(client_options_instance@.internal_rcpp_object$set_session_type(session_type)) - } -) - -setGeneric( - "use_tls", - function(client_options_instance, ...) { - return(standardGeneric("use_tls")) - }, - signature = "client_options_instance" -) - -#' @export -setMethod( - "use_tls", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, root_certs = "") { - verify_string("root_certs", root_certs, TRUE) - return(client_options_instance@.internal_rcpp_object$set_tls_root_certs(root_certs)) - } -) - -setGeneric( - "add_int_option", - function(client_options_instance, opt, val) { - return(standardGeneric("add_int_option")) - }, - signature = c("client_options_instance", "opt", "val") -) - -#' @export -setMethod( - "add_int_option", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, opt, val) { - verify_string("opt", opt, TRUE) - verify_any_int("val", val, TRUE) - return(client_options_instance@.internal_rcpp_object$add_int_option(opt, val)) - } -) - -setGeneric( - "add_string_option", - function(client_options_instance, opt, val) { - return(standardGeneric("add_string_option")) - }, - signature = c("client_options_instance", "opt", "val") -) - -#' @export -setMethod( - "add_string_option", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, opt, val) { - verify_string("opt", opt, TRUE) - verify_string("val", val, TRUE) - return(client_options_instance@.internal_rcpp_object$add_string_option(opt, val)) - } -) - -setGeneric( - "add_extra_header", - function(client_options_instance, header_name, header_val) { - return(standardGeneric("add_extra_header")) - }, - signature = c("client_options_instance", "header_name", "header_val") -) - -#' @export -setMethod( - "add_extra_header", - signature = c(client_options_instance = "S4ClientOptions"), - function(client_options_instance, header_name, header_val) { - verify_string("header_name", header_name, TRUE) - verify_string("header_value", header_value, TRUE) - return(client_options_instance@.internal_rcpp_object$add_extra_header(opt, val)) - } -) diff --git a/R/rdeephaven/R/new_client_wrapper.R b/R/rdeephaven/R/new_client_wrapper.R index a7041969807..5dd38045a0d 100644 --- a/R/rdeephaven/R/new_client_wrapper.R +++ b/R/rdeephaven/R/new_client_wrapper.R @@ -1,6 +1,6 @@ #' @export setClass( - "S4Client", + "Client", representation( .internal_rcpp_object = "Rcpp_INTERNAL_Client" ) @@ -8,25 +8,118 @@ setClass( setGeneric( "connect", - function(target, client_options) { + function(target, ...) { return(standardGeneric("connect")) }, - signature = c("target", "client_options") + signature = c("target") ) #' @export setMethod( "connect", - signature = c(target = "character", client_options = "S4ClientOptions"), - function(target, client_options) { + signature = c(target = "character"), + function(target, + auth_type = "anonymous", + auth_token_pair = "", + session_type = "python", + use_tls = FALSE, + tls_root_certs = "", + int_option = "", + string_option = "", + extra_header = "") { + + options <- new(INTERNAL_ClientOptions) + + # check if auth_type needs to be changed and set credentials accordingly + if(auth_type != "anonymous") { + if(auth_type == "basic") { + if(auth_token_pair != "") { + username_password <- strsplit(auth_token_pair, ":", fixed = TRUE) + options$set_basic_authentication(username_password[1], username_password[2]) + } + else { + stop("Basic authentication was requested, but no 'auth_token_pair' was provided.") + } + } + else if(auth_type == "custom") { + if(auth_token_pair != "") { + key_value <- strsplit(auth_token_pair, ":", fixed = TRUE) + options$set_custom_authentication(key_value[1], key_value[2]) + } + else { + stop("Custom authentication was requested, but no 'auth_token_pair' was provided.") + } + } + else { + stop(paste0("'auth_type' must be 'anonymous', 'basic', or 'custom', but got ", auth_type, " instead.")) + } + } + + # set session type if a valid session type is provided + if((session_type == "python") || (session_type == "groovy")) { + options$set_session_type(session_type) + } + else { + stop(paste0("'session_type' must be 'python' or 'groovy', but got ", session_type, " instead.")) + } + + # if tls is requested, set it and set the root_certs if provided + if(use_tls != FALSE) { + if(use_tls == TRUE) { + options$set_use_tls() + if(tls_root_certs != "") { + options$set_tls_root_certs(tls_root_certs) + } + } + else { + stop(paste0("'use_tls' must be TRUE or FALSE, but got ", use_tls, " instead.")) + } + } + + if(int_option != "") { + new_int_option <- strsplit(int_option, ":", fixed = TRUE) + options$add_int_option(new_int_option[1], as.numeric(new_int_option[2])) + } + + if(string_option != "") { + new_string_option <- strsplit(string_option, ":", fixed = TRUE) + options$add_string_option(new_string_option[1], new_string_option[2]) + } + + if(extra_header != "") { + new_extra_header <- strsplit(extra_header, ":", fixed = TRUE) + options$add_extra_header(new_extra_header[1], new_extra_header[2]) + } + internal_client <- new(INTERNAL_Client, target = target, - client_options = client_options@.internal_rcpp_object + client_options = options ) - return(new("S4Client", .internal_rcpp_object = internal_client)) + return(new("Client", .internal_rcpp_object = internal_client)) } ) +#' setGeneric( +#' "connect", +#' function(target, client_options) { +#' return(standardGeneric("connect")) +#' }, +#' signature = c("target", "client_options") +#' ) +#' +#' #' @export +#' setMethod( +#' "connect", +#' signature = c(target = "character", client_options = "ClientOptions"), +#' function(target, client_options) { +#' internal_client <- new(INTERNAL_Client, +#' target = target, +#' client_options = client_options@.internal_rcpp_object +#' ) +#' return(new("Client", .internal_rcpp_object = internal_client)) +#' } +#' ) + ### HELPER FUNCTIONS ### # These functions return RC objects returned by Rcpp without wrapping them in S4 @@ -68,13 +161,13 @@ setGeneric( #' @export setMethod( "open_table", - signature = c(client_instance = "S4Client"), + signature = c(client_instance = "Client"), function(client_instance, name) { verify_string("name", name, TRUE) if (!check_for_table(client_instance, name)) { stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) } - return(new("S4TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$open_table(name))) + return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$open_table(name))) } ) @@ -89,10 +182,10 @@ setGeneric( #' @export setMethod( "empty_table", - signature = c(client_instance = "S4Client"), + signature = c(client_instance = "Client"), function(client_instance, size) { verify_positive_int("size", size, TRUE) - return(new("S4TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$empty_table(size))) + return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$empty_table(size))) } ) @@ -107,11 +200,11 @@ setGeneric( #' @export setMethod( "time_table", - signature = c(client_instance = "S4Client"), + signature = c(client_instance = "Client"), function(client_instance, period_nanos, start_time_nanos = 0) { verify_any_int("period_nanos", period_nanos, TRUE) verify_any_int("start_time_nanos", start_time_nanos, TRUE) - return(new("S4TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$time_table(start_time_nanos, period_nanos))) + return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$time_table(start_time_nanos, period_nanos))) } ) @@ -126,7 +219,7 @@ setGeneric( #' @export setMethod( "import_table", - signature = c(client_instance = "S4Client"), + signature = c(client_instance = "Client"), function(client_instance, table_object) { table_object_class <- class(table_object) @@ -148,7 +241,7 @@ setMethod( else { stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], " instead.")) } - return(new("S4TableHandle", .internal_rcpp_object = rcpp_dh_table)) + return(new("TableHandle", .internal_rcpp_object = rcpp_dh_table)) } ) @@ -163,7 +256,7 @@ setGeneric( #' @export setMethod( "run_script", - signature = c(client_instance = "S4Client"), + signature = c(client_instance = "Client"), function(client_instance, script) { verify_string("script", script, TRUE) client_instance@.internal_rcpp_object$run_script(script) @@ -175,7 +268,7 @@ setMethod( #' @export setMethod( "close", - signature = c(con = "S4Client"), + signature = c(con = "Client"), function(con) { con@.internal_rcpp_object$close() return(NULL) diff --git a/R/rdeephaven/R/new_table_handle_wrapper.R b/R/rdeephaven/R/new_table_handle_wrapper.R index 661e7a25511..b6e83fac08f 100644 --- a/R/rdeephaven/R/new_table_handle_wrapper.R +++ b/R/rdeephaven/R/new_table_handle_wrapper.R @@ -1,9 +1,6 @@ -#' @importFrom arrow as_arrow_table RecordBatchStreamReader -#' @importFrom dplyr as_tibble - #' @export setClass( - "S4TableHandle", + "TableHandle", representation( .internal_rcpp_object = "Rcpp_INTERNAL_TableHandle" ) @@ -22,7 +19,7 @@ setGeneric( #' @export setMethod( "is_static", - signature = c(table_handle_instance = "S4TableHandle"), + signature = c(table_handle_instance = "TableHandle"), function(table_handle_instance) { return(table_handle_instance@.internal_rcpp_object$is_static()) } @@ -31,21 +28,29 @@ setMethod( #' @export setMethod( "head", - signature = c(x = "S4TableHandle"), + signature = c(x = "TableHandle"), function(x, n, ...) { verify_positive_int("n", n, TRUE) - return(new("S4TableHandle", .internal_rcpp_object = x@.internal_rcpp_object$head(n))) + return(new("TableHandle", .internal_rcpp_object = x@.internal_rcpp_object$head(n))) } ) #' @export setMethod( "tail", - signature = c(x = "S4TableHandle"), + signature = c(x = "TableHandle"), function(x, n, ...) { - print("I'm here!") verify_positive_int("n", n, TRUE) - return(new("S4TableHandle", .internal_rcpp_object = x@.internal_rcpp_object$tail(n))) + return(new("TableHandle", .internal_rcpp_object = x@.internal_rcpp_object$tail(n))) + } +) + +#' @export +setMethod( + "nrow", + signature = c(x = "TableHandle"), + function(x) { + return(x@.internal_rcpp_object$num_rows()) } ) @@ -53,19 +58,10 @@ setMethod( ### TABLEHANDLE CONVERSIONS ### -# could potentially be implemented by other packages -setGeneric( - "as_arrow_record_batch_stream_reader", - function(x, ...) { - return(standardGeneric("as_arrow_record_batch_stream_reader")) - }, - signature = c("x") -) - #' @export setMethod( - "as_arrow_record_batch_stream_reader", - signature = c(x = "S4TableHandle"), + "as_record_batch_reader", + signature = c(x = "TableHandle"), function(x, ...) { ptr <- x@.internal_rcpp_object$get_arrow_array_stream_ptr() rbsr <- RecordBatchStreamReader$import_from_c(ptr) @@ -76,9 +72,9 @@ setMethod( #' @export setMethod( "as_arrow_table", - signature = c(x = "S4TableHandle"), + signature = c(x = "TableHandle"), function(x, ...) { - rbsr <- as_arrow_record_batch_stream_reader(x) + rbsr <- as_record_batch_reader(x) arrow_tbl <- rbsr$read_table() return(arrow_tbl) } @@ -87,9 +83,9 @@ setMethod( #' @export setMethod( "as_tibble", - signature = c(x = "S4TableHandle"), + signature = c(x = "TableHandle"), function(x, ...) { - rbsr <- as_arrow_record_batch_stream_reader(x) + rbsr <- as_record_batch_reader(x) arrow_tbl <- rbsr$read_table() return(as_tibble(arrow_tbl)) } @@ -98,7 +94,7 @@ setMethod( #' @export setMethod( "as.data.frame", - signature = c(x = "S4TableHandle"), + signature = c(x = "TableHandle"), function(x, ...) { arrow_tbl <- as_arrow_table(x) return(as.data.frame(as.data.frame(arrow_tbl))) @@ -118,7 +114,7 @@ setGeneric( #' @export setMethod( "bind_to_variable", - signature = c(table_handle_instance = "S4TableHandle"), + signature = c(table_handle_instance = "TableHandle"), function(table_handle_instance, name) { verify_string("name", name, TRUE) table_handle_instance@.internal_rcpp_object$bind_to_variable(name) diff --git a/R/rdeephaven/R/new_table_ops.R b/R/rdeephaven/R/new_table_ops.R index 6fdd695e9ce..d160cc484f5 100644 --- a/R/rdeephaven/R/new_table_ops.R +++ b/R/rdeephaven/R/new_table_ops.R @@ -1,6 +1,6 @@ setGeneric( "select", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { return(standardGeneric("select")) }, signature = c("table_handle", "columns") @@ -9,16 +9,16 @@ setGeneric( #' @export setMethod( "select", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$select(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$select(columns))) } ) setGeneric( "view", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { return(standardGeneric("view")) }, signature = c("table_handle", "columns") @@ -27,16 +27,16 @@ setGeneric( #' @export setMethod( "view", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$view(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$view(columns))) } ) setGeneric( "update", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("update") }, signature = c("table_handle", "columns") @@ -45,16 +45,16 @@ setGeneric( #' @export setMethod( "update", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update(columns))) } ) setGeneric( "update_view", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("update_view") }, signature = c("table_handle", "columns") @@ -63,16 +63,16 @@ setGeneric( #' @export setMethod( "update_view", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update_view(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update_view(columns))) } ) setGeneric( "drop_columns", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("drop_columns") }, signature = c("table_handle", "columns") @@ -81,10 +81,10 @@ setGeneric( #' @export setMethod( "drop_columns", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$drop_columns(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$drop_columns(columns))) } ) @@ -99,16 +99,16 @@ setGeneric( #' @export setMethod( "where", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, condition) { verify_string("condition", condition, TRUE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$where(condition))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$where(condition))) } ) setGeneric( "group_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("group_by") }, signature = c("table_handle", "columns") @@ -117,16 +117,16 @@ setGeneric( #' @export setMethod( "group_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$group_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$group_by(columns))) } ) setGeneric( "ungroup", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("ungroup") }, signature = c("table_handle", "columns") @@ -135,38 +135,37 @@ setGeneric( #' @export setMethod( "ungroup", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$ungroup(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$ungroup(columns))) } ) setGeneric( "agg_by", - function(table_handle, aggregations, columns, ...) { + function(table_handle, aggregations, columns = character(), ...) { standardGeneric("agg_by") }, signature = c("table_handle", "aggregations", "columns") ) -# WILL MOT WORK YET #' @export setMethod( "agg_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, aggregations, columns = character()) { verify_type("aggregations", aggregations, "Aggregation", "Deephaven Aggregation", FALSE) verify_string("columns", columns, FALSE) aggregations <- c(aggregations) unwrapped_aggregations <- lapply(aggregations, strip_s4_wrapping) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$agg_by(unwrapped_aggregations, columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$agg_by(unwrapped_aggregations, columns))) } ) setGeneric( "first_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("first_by") }, signature = c("table_handle", "columns") @@ -175,16 +174,16 @@ setGeneric( #' @export setMethod( "first_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$first_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$first_by(columns))) } ) setGeneric( "last_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("last_by") }, signature = c("table_handle", "columns") @@ -193,16 +192,16 @@ setGeneric( #' @export setMethod( "last_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$last_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$last_by(columns))) } ) setGeneric( "head_by", - function(table_handle, n, columns, ...) { + function(table_handle, n, columns = character(), ...) { standardGeneric("head_by") }, signature = c("table_handle", "n", "columns") @@ -211,17 +210,17 @@ setGeneric( #' @export setMethod( "head_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, n, columns = character()) { verify_positive_int("n", n, TRUE) verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$head_by(n, columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$head_by(n, columns))) } ) setGeneric( "tail_by", - function(table_handle, n, columns, ...) { + function(table_handle, n, columns = character(), ...) { standardGeneric("tail_by") }, signature = c("table_handle", "n", "columns") @@ -230,17 +229,17 @@ setGeneric( #' @export setMethod( "tail_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, n, columns = character()) { verify_positive_int("n", n, TRUE) verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$tail_by(n, columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$tail_by(n, columns))) } ) setGeneric( "min_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("min_by") }, signature = c("table_handle", "columns") @@ -249,16 +248,16 @@ setGeneric( #' @export setMethod( "min_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$min_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$min_by(columns))) } ) setGeneric( "max_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("max_by") }, signature = c("table_handle", "columns") @@ -267,16 +266,16 @@ setGeneric( #' @export setMethod( "max_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$max_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$max_by(columns))) } ) setGeneric( "sum_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("sum_by") }, signature = c("table_handle", "columns") @@ -285,16 +284,16 @@ setGeneric( #' @export setMethod( "sum_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sum_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sum_by(columns))) } ) setGeneric( "abs_sum_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("abs_sum_by") }, signature = c("table_handle", "columns") @@ -303,16 +302,16 @@ setGeneric( #' @export setMethod( "abs_sum_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$abs_sum_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$abs_sum_by(columns))) } ) setGeneric( "avg_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("avg_by") }, signature = c("table_handle", "columns") @@ -321,16 +320,16 @@ setGeneric( #' @export setMethod( "avg_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$avg_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$avg_by(columns))) } ) setGeneric( "w_avg_by", - function(table_handle, weight_column, columns, ...) { + function(table_handle, weight_column, columns = character(), ...) { standardGeneric("w_avg_by") }, signature = c("table_handle", "weight_column", "columns") @@ -339,17 +338,17 @@ setGeneric( #' @export setMethod( "w_avg_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, weight_column, columns = character()) { verify_string("weight_column", weight_column, TRUE) verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$w_avg_by(weight_column, columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$w_avg_by(weight_column, columns))) } ) setGeneric( "median_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("median_by") }, signature = c("table_handle", "columns") @@ -358,16 +357,16 @@ setGeneric( #' @export setMethod( "median_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$median_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$median_by(columns))) } ) setGeneric( "var_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("var_by") }, signature = c("table_handle", "columns") @@ -376,16 +375,16 @@ setGeneric( #' @export setMethod( "var_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$var_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$var_by(columns))) } ) setGeneric( "std_by", - function(table_handle, columns, ...) { + function(table_handle, columns = character(), ...) { standardGeneric("std_by") }, signature = c("table_handle", "columns") @@ -394,16 +393,16 @@ setGeneric( #' @export setMethod( "std_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns = character()) { verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$std_by(columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$std_by(columns))) } ) setGeneric( "percentile_by", - function(table_handle, percentile, columns, ...) { + function(table_handle, percentile, columns = character(), ...) { standardGeneric("percentile_by") }, signature = c("table_handle", "percentile", "columns") @@ -412,17 +411,17 @@ setGeneric( #' @export setMethod( "percentile_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, percentile, columns = character()) { verify_in_unit_interval("percentile", percentile, TRUE) verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$percentile_by(percentile, columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$percentile_by(percentile, columns))) } ) setGeneric( "count_by", - function(table_handle, count_by_column, columns, ...) { + function(table_handle, count_by_column, columns = character(), ...) { standardGeneric("count_by") }, signature = c("table_handle", "count_by_column", "columns") @@ -431,11 +430,11 @@ setGeneric( #' @export setMethod( "count_by", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, count_by_column = "n", columns = character()) { verify_string("count_by_column", count_by_column, TRUE) verify_string("columns", columns, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$count_by(count_by_column, columns))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$count_by(count_by_column, columns))) } ) @@ -450,12 +449,12 @@ setGeneric( #' @export setMethod( "cross_join", - signature = c(table_handle = "S4TableHandle", right_side = "S4TableHandle"), + signature = c(table_handle = "TableHandle", right_side = "TableHandle"), function(table_handle, right_side, columns_to_match = character(), columns_to_add = character()) { verify_string("columns_to_match", columns_to_match, FALSE) verify_string("columns_to_add", columns_to_add, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$cross_join( - right_side@internal_table_handle, + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$cross_join( + right_side@.internal_rcpp_object, columns_to_match, columns_to_add ))) } @@ -472,12 +471,12 @@ setGeneric( #' @export setMethod( "natural_join", - signature = c(table_handle = "S4TableHandle", right_side = "S4TableHandle"), + signature = c(table_handle = "TableHandle", right_side = "TableHandle"), function(table_handle, right_side, columns_to_match = character(), columns_to_add = character()) { verify_string("columns_to_match", columns_to_match, FALSE) verify_string("columns_to_add", columns_to_add, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$natural_join( - right_side@internal_table_handle, + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$natural_join( + right_side@.internal_rcpp_object, columns_to_match, columns_to_add ))) } @@ -494,22 +493,21 @@ setGeneric( #' @export setMethod( "exact_join", - signature = c(table_handle = "S4TableHandle", right_side = "S4TableHandle"), + signature = c(table_handle = "TableHandle", right_side = "TableHandle"), function(table_handle, right_side, columns_to_match = character(), columns_to_add = character()) { verify_string("columns_to_match", columns_to_match, FALSE) verify_string("columns_to_add", columns_to_add, FALSE) - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$exact_join( - right_side@internal_table_handle, + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$exact_join( + right_side@.internal_rcpp_object, columns_to_match, columns_to_add ))) } ) -# Will not work yet! #' @export setGeneric( "sort", - function(table_handle, columns, descending, ...) { + function(table_handle, columns = character(), descending = FALSE, ...) { standardGeneric("sort") }, signature = c("table_handle", "columns", "descending") @@ -518,14 +516,14 @@ setGeneric( #' @export setMethod( "sort", - signature = c(table_handle = "S4TableHandle"), + signature = c(table_handle = "TableHandle"), function(table_handle, columns, descending = FALSE) { verify_string("columns", columns, FALSE) verify_bool("descending", descending, FALSE) if ((length(descending) > 1) && length(descending) != length(columns)) { stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) } - return(new("S4TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(columns, descending))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(columns, descending))) } ) diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index d728b5d3a67..7813b510816 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -1,4 +1,5 @@ library(testthat) +library(dplyr) library(rdeephaven) setup <- function() { @@ -41,16 +42,15 @@ setup <- function() { # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() # set up client - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- client$import_table(df1) - th2 <- client$import_table(df2) - th3 <- client$import_table(df3) - th4 <- client$import_table(df4) - th5 <- client$import_table(df5) - th6 <- client$import_table(df6) + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) + th5 <- import_table(client, df5) + th6 <- import_table(client, df6) return(list( "client" = client, @@ -110,7 +110,7 @@ test_that("agg_first behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_last behaves as expected", { @@ -164,7 +164,7 @@ test_that("agg_last behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_min behaves as expected", { @@ -218,7 +218,7 @@ test_that("agg_min behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_max behaves as expected", { @@ -272,7 +272,7 @@ test_that("agg_max behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_sum behaves as expected", { @@ -326,7 +326,7 @@ test_that("agg_sum behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_abs_sum behaves as expected", { @@ -380,7 +380,7 @@ test_that("agg_abs_sum behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_avg behaves as expected", { @@ -434,7 +434,7 @@ test_that("agg_avg behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_w_avg behaves as expected", { @@ -498,7 +498,7 @@ test_that("agg_w_avg behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_median behaves as expected", { @@ -552,7 +552,7 @@ test_that("agg_median behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_var behaves as expected", { @@ -606,7 +606,7 @@ test_that("agg_var behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_std behaves as expected", { @@ -660,7 +660,7 @@ test_that("agg_std behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) test_that("agg_percentile behaves as expected", { @@ -695,7 +695,7 @@ test_that("agg_percentile behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th3), new_df3) - data$client$close() + close(data$client) }) test_that("agg_count behaves as expected", { @@ -743,5 +743,5 @@ test_that("agg_count behaves as expected", { sort(c("X", "Y")) expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - data$client$close() + close(data$client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R index 66ef76537c8..9f305f71933 100644 --- a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R @@ -3,13 +3,6 @@ library(rdeephaven) ##### TESTING BAD INPUTS ##### -test_that("trying to instantiate an Aggregation fails nicely", { - expect_error( - Aggregation$new("hello"), - "'aggregation' should be an internal Deephaven Aggregation. If you're seeing this,\n you are trying to call the constructor of an Aggregation directly, which is not advised.\n Please use one of the provided aggregation functions instead." - ) -}) - test_that("agg_min fails nicely when 'columns' is a bad type", { expect_error( agg_min(5), diff --git a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R deleted file mode 100644 index 706f5ac4f69..00000000000 --- a/R/rdeephaven/inst/tests/testthat/test_client_options_wrapper.R +++ /dev/null @@ -1,163 +0,0 @@ -library(testthat) -library(rdeephaven) - -##### TESTING GOOD INPUTS ##### - -test_that("initializing ClientOptions does not throw an error", { - expect_no_error(client_options <- ClientOptions$new()) -}) - -test_that("setting default authentication does not throw an error", { - client_options <- ClientOptions$new() - expect_no_error(client_options$set_default_authentication()) -}) - -test_that("setting basic authentication with string inputs does not throw an error", { - client_options <- ClientOptions$new() - expect_no_error(client_options$set_basic_authentication("my_username", "my_password")) -}) - -test_that("setting custom authentication with string inputs does not throw an error", { - client_options <- ClientOptions$new() - expect_no_error(client_options$set_custom_authentication("my_key", "my_value")) -}) - -test_that("setting session type to python does not throw an error", { - client_options <- ClientOptions$new() - expect_no_error(client_options$set_session_type("python")) -}) - -test_that("setting session type to groovy does not throw an error", { - client_options <- ClientOptions$new() - expect_no_error(client_options$set_session_type("groovy")) -}) - -##### TESTING BAD INPUTS ##### - -test_that("setting basic authentication with bad input types fails nicely", { - client_options <- ClientOptions$new() - expect_error( - client_options$set_basic_authentication(12345, "my_password"), - "'username' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$set_basic_authentication("my_username", 12345), - "'password' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$set_basic_authentication(c("I", "am", "a", "string"), "my_password"), - "'username' must be passed as a single string. Got a string vector of length 4 instead." - ) - expect_error( - client_options$set_basic_authentication("my_username", c("I", "am", "a", "string")), - "'password' must be passed as a single string. Got a string vector of length 4 instead." - ) -}) - -test_that("setting custom authentication with bad input types fails nicely", { - client_options <- ClientOptions$new() - expect_error( - client_options$set_custom_authentication(12345, "my_auth_value"), - "'auth_key' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$set_custom_authentication("my_auth_key", 12345), - "'auth_value' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$set_custom_authentication(c("I", "am", "a", "string"), "my_auth_value"), - "'auth_key' must be passed as a single string. Got a string vector of length 4 instead." - ) - expect_error( - client_options$set_custom_authentication("my_auth_key", c("I", "am", "a", "string")), - "'auth_value' must be passed as a single string. Got a string vector of length 4 instead." - ) -}) - -test_that("setting bad session type fails nicely", { - client_options <- ClientOptions$new() - expect_error( - client_options$set_session_type(12345), - "'session_type' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$set_session_type(c("I", "am", "string")), - "'session_type' must be passed as a single string. Got a string vector of length 3 instead." - ) -}) - -test_that("using tls with bad input type fails nicely", { - client_options <- ClientOptions$new() - expect_error( - client_options$use_tls(12345), - "'root_certs' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$use_tls(c("double", "string")), - "'root_certs' must be passed as a single string. Got a string vector of length 2 instead." - ) -}) - -test_that("add_int_option with bad types fails nicely", { - client_options <- ClientOptions$new() - expect_error( - client_options$add_int_option(12345, 12345), - "'opt' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$add_int_option(c("several", "strings"), 12345), - "'opt' must be passed as a single string. Got a string vector of length 2 instead." - ) - expect_error( - client_options$add_int_option("option_key", "blah blah"), - "'val' must be passed as a single numeric. Got an object of class character instead." - ) - expect_error( - client_options$add_int_option("option_key", 12345.6789), - "'val' must be an integer. Got 'val' = 12345.6789 instead." - ) - expect_error( - client_options$add_int_option("option_key", c(1, 2, 3, 4, 5)), - "'val' must be passed as a single numeric. Got a numeric vector of length 5 instead." - ) -}) - -test_that("add_string_option with bad types fails nicely", { - client_options <- ClientOptions$new() - expect_error( - client_options$add_string_option(12345, "option_val"), - "'opt' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$add_string_option(c("several", "strings"), "option_val"), - "'opt' must be passed as a single string. Got a string vector of length 2 instead." - ) - expect_error( - client_options$add_string_option("option_key", 12345), - "'val' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$add_string_option("option_key", c("several", "many", "strings")), - "'val' must be passed as a single string. Got a string vector of length 3 instead." - ) -}) - -test_that("add_extra_header with bad types fails nicely", { - client_options <- ClientOptions$new() - expect_error( - client_options$add_extra_header(12345, "header_value"), - "'header_name' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$add_extra_header(c("several", "strings"), "header_value"), - "'header_name' must be passed as a single string. Got a string vector of length 2 instead." - ) - expect_error( - client_options$add_extra_header("header_name", 12345), - "'header_value' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client_options$add_extra_header("header_name", c("several", "many", "strings")), - "'header_value' must be passed as a single string. Got a string vector of length 3 instead." - ) -}) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index fb10cbc62e2..871bc9248a6 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -28,122 +28,110 @@ setup <- function() { ##### TESTING GOOD INPUTS ##### test_that("client connection works in the simple case of anonymous authentication", { - # assumes correctness of client options - client_options <- ClientOptions$new() # TODO: assumes server is actually running on localhost:10000, this is probably bad for CI - expect_no_error(client <- Client$new(target = "localhost:10000", client_options = client_options)) - - client$close() + expect_no_error(client <- connect(target = "localhost:10000")) + }) -# All of the following tests assume the correctness of Client$new(...) to make the connection. +# All of the following tests assume the correctness of new(...) to make the connection. test_that("import_table does not fail with data frame inputs of simple column types", { data <- setup() - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_no_error(client$import_table(data$df1)) - expect_no_error(client$import_table(data$df2)) - expect_no_error(client$import_table(data$df3)) - expect_no_error(client$import_table(data$df4)) + expect_no_error(import_table(client, data$df1)) + expect_no_error(import_table(client, data$df2)) + expect_no_error(import_table(client, data$df3)) + expect_no_error(import_table(client, data$df4)) - client$close() + close(client) }) test_that("import_table does not fail with tibble inputs of simple column types", { data <- setup() - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_no_error(client$import_table(as_tibble(data$df1))) - expect_no_error(client$import_table(as_tibble(data$df2))) - expect_no_error(client$import_table(as_tibble(data$df3))) - expect_no_error(client$import_table(as_tibble(data$df4))) + expect_no_error(import_table(client, as_tibble(data$df1))) + expect_no_error(import_table(client, as_tibble(data$df2))) + expect_no_error(import_table(client, as_tibble(data$df3))) + expect_no_error(import_table(client, as_tibble(data$df4))) - client$close() + close(client) }) test_that("import_table does not fail with arrow table inputs of simple column types", { data <- setup() - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_no_error(client$import_table(arrow_table(data$df1))) - expect_no_error(client$import_table(arrow_table(data$df2))) - expect_no_error(client$import_table(arrow_table(data$df3))) - expect_no_error(client$import_table(arrow_table(data$df4))) + expect_no_error(import_table(client, as_arrow_table(data$df1))) + expect_no_error(import_table(client, as_arrow_table(data$df2))) + expect_no_error(import_table(client, as_arrow_table(data$df3))) + expect_no_error(import_table(client, as_arrow_table(data$df4))) - client$close() + close(client) }) test_that("import_table does not fail with record batch reader inputs of simple column types", { data <- setup() - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df1)))) - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df2)))) - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df3)))) - expect_no_error(client$import_table(as_record_batch_reader(arrow_table(data$df4)))) + expect_no_error(import_table(client, as_record_batch_reader(data$df1))) + expect_no_error(import_table(client, as_record_batch_reader(data$df2))) + expect_no_error(import_table(client, as_record_batch_reader(data$df3))) + expect_no_error(import_table(client, as_record_batch_reader(data$df4))) - client$close() + close(client) }) -# The following tests additionally assume the correctness of client$import_table(...) AND table_handle$bind_to_variable(), -# as we have to create data, push it to the server, and name it in order to test client$open_table(). +# The following tests additionally assume the correctness of import_table(...) AND table_handle$bind_to_variable(), +# as we have to create data, push it to the server, and name it in order to test open_table(). # Additionally, we assume the correctness of table_handle$to_data_frame() to make concrete comparisons. test_that("open_table opens the correct table from the server", { data <- setup() - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - th1 <- client$import_table(data$df1) - th1$bind_to_variable("table1") - expect_equal(client$open_table("table1")$to_data_frame(), th1$to_data_frame()) + th1 <- import_table(client, data$df1) + th1 %>% bind_to_variable("table1") + expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) - th2 <- client$import_table(data$df2) - th2$bind_to_variable("table2") - expect_equal(client$open_table("table2")$to_data_frame(), th2$to_data_frame()) + th2 <- import_table(client, data$df2) + th2 %>% bind_to_variable("table2") + expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) - th3 <- client$import_table(data$df3) - th3$bind_to_variable("table3") - expect_equal(client$open_table("table3")$to_data_frame(), th3$to_data_frame()) + th3 <- import_table(client, data$df3) + th3 %>% bind_to_variable("table3") + expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) - th4 <- client$import_table(data$df4) - th4$bind_to_variable("table4") - expect_equal(client$open_table("table4")$to_data_frame(), th4$to_data_frame()) + th4 <- import_table(client, data$df4) + th4 %>% bind_to_variable("table4") + expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) - client$close() + close(client) }) test_that("empty_table correctly creates tables on the server", { - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) - - th1 <- client$empty_table(10) %>% update("X = i") - expect_equal(th1$nrow(), 10) + client <- connect(target = "localhost:10000") - th2 <- client$empty_table(1234567) %>% update("X = i") - expect_equal(th2$nrow(), 1234567) + th1 <- empty_table(client, 10) %>% update("X = i") + df1 <- data.frame(X = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) + expect_equal(as.data.frame(th1), df1) - client$close() + close(client) }) # TODO: Test time_table good inputs test_that("run_script correctly runs a python script", { - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_no_error(client$run_script( + expect_no_error(run_script(client, ' from deephaven import new_table from deephaven.column import string_col, int_col @@ -155,123 +143,83 @@ int_col("Name_Int_Col", [44, 55, 66]) ' )) - expect_no_error(client$open_table("static_table_from_python_script")) + expect_no_error(open_table(client, "static_table_from_python_script")) - client$close() + close(client) }) ##### TESTING BAD INPUTS ##### -test_that("client connection fails nicely with bad target but good client_options", { - # assumes correctness of client options - client_options <- ClientOptions$new() - - # TODO: Bad address needs better error handling from the R side - expect_error(client <- Client$new(target = "bad address", client_options = client_options)) - expect_error( - client <- Client$new(target = 12345, client_options = client_options), - "'target' must be passed as a single string. Got an object of class numeric instead." - ) - expect_error( - client <- Client$new(target = c("hello", "my", "name", "is"), client_options = client_options), - "'target' must be passed as a single string. Got a string vector of length 4 instead." - ) -}) - -test_that("client connection fails nicely with good target but bad client_options", { - # TODO: these all assume that the server is actually running on localhost:10000, probably bad for CI - expect_error( - client <- Client$new(target = "localhost:10000", client_options = "bad"), - "'client_options' should be a Deephaven ClientOptions object. Got an object of type character instead." - ) - expect_error( - client <- Client$new(target = "localhost:10000", client_options = 12345), - "'client_options' should be a Deephaven ClientOptions object. Got an object of type numeric instead." - ) - - # TODO: Invalid auth details needs better error handling from the R side - bad_client_options1 <- ClientOptions$new() - bad_client_options1$set_basic_authentication("my_username", "my_password") - expect_error(client <- Client$new(target = "localhost:10000", client_options = bad_client_options1)) - - bad_client_options2 <- ClientOptions$new() - bad_client_options2$set_session_type("groovy") - expect_error(client <- Client$new(target = "localhost:10000", client_options = bad_client_options2)) -}) +# FAILS +# TODO: Test all of the new client connections stuff test_that("import_table fails nicely with bad inputs", { library(datasets) - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") expect_error( - client$import_table(12345), + import_table(client, 12345), "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class numeric instead." ) expect_error( - client$import_table("hello!"), + import_table(client, "hello!"), "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class character instead." ) # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. data(iris) - expect_error(client$import_table(iris)) + expect_error(import_table(client, iris)) data(HairEyeColor) expect_error( - client$import_table(HairEyeColor), + import_table(client, HairEyeColor), "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class table instead." ) - client$close() + close(client) }) test_that("open_table fails nicely with bad inputs", { - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_error(client$open_table(""), "The table '' you're trying to pull does not exist on the server.") - expect_error(client$open_table(12345), "'name' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client$open_table(client_options), "'name' must be passed as a single string. Got an object of class ClientOptions instead.") - expect_error(client$open_table(c("I", "am", "string")), "'name' must be passed as a single string. Got a string vector of length 3 instead.") + expect_error(open_table(client, ""), "The table '' you're trying to pull does not exist on the server.") + expect_error(open_table(client, 12345), "'name' must be passed as a single string. Got an object of class numeric instead.") + expect_error(open_table(client, c("I", "am", "string")), "'name' must be passed as a single string. Got a string vector of length 3 instead.") - client$close() + close(client) }) test_that("empty_table fails nicely with bad inputs", { - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_error(client$empty_table(0), "'size' must be a positive integer. Got 'size' = 0 instead.") - expect_error(client$empty_table(-3), "'size' must be a positive integer. Got 'size' = -3 instead.") - expect_error(client$empty_table(1.2345), "'size' must be an integer. Got 'size' = 1.2345 instead.") - expect_error(client$empty_table("hello!"), "'size' must be passed as a single numeric. Got an object of class character instead.") - expect_error(client$empty_table(c(1, 2, 3, 4)), "'size' must be passed as a single numeric. Got a numeric vector of length 4 instead.") + expect_error(empty_table(client, 0), "'size' must be a positive integer. Got 'size' = 0 instead.") + expect_error(empty_table(client, -3), "'size' must be a positive integer. Got 'size' = -3 instead.") + expect_error(empty_table(client, 1.2345), "'size' must be an integer. Got 'size' = 1.2345 instead.") + expect_error(empty_table(client, "hello!"), "'size' must be passed as a single numeric. Got an object of class character instead.") + expect_error(empty_table(client, c(1, 2, 3, 4)), "'size' must be passed as a single numeric. Got a numeric vector of length 4 instead.") - client$close() + close(client) }) test_that("time_table fails nicely with bad inputs", { - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_error(client$time_table(1.23, 1000), "'period_nanos' must be an integer. Got 'period_nanos' = 1.23 instead.") - expect_error(client$time_table(1000, 1.23), "'start_time_nanos' must be an integer. Got 'start_time_nanos' = 1.23 instead.") - expect_error(client$time_table(c(1, 2, 3), 1000), "'period_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") - expect_error(client$time_table(1000, c(1, 2, 3)), "'start_time_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") - expect_error(client$time_table("hello!", 1000), "'period_nanos' must be passed as a single numeric. Got an object of class character instead.") - expect_error(client$time_table(1000, "hello!"), "'start_time_nanos' must be passed as a single numeric. Got an object of class character instead.") + expect_error(time_table(client, 1.23, 1000), "'period_nanos' must be an integer. Got 'period_nanos' = 1.23 instead.") + expect_error(time_table(client, 1000, 1.23), "'start_time_nanos' must be an integer. Got 'start_time_nanos' = 1.23 instead.") + expect_error(time_table(client, c(1, 2, 3), 1000), "'period_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") + expect_error(time_table(client, 1000, c(1, 2, 3)), "'start_time_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") + expect_error(time_table(client, "hello!", 1000), "'period_nanos' must be passed as a single numeric. Got an object of class character instead.") + expect_error(time_table(client, 1000, "hello!"), "'start_time_nanos' must be passed as a single numeric. Got an object of class character instead.") - client$close() + close(client) }) test_that("run_script fails nicely with bad input types", { - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") - expect_error(client$run_script(12345), "'script' must be passed as a single string. Got an object of class numeric instead.") - expect_error(client$run_script(c("I", "am", "a", "string")), "'script' must be passed as a single string. Got a string vector of length 4 instead.") + expect_error(run_script(client, 12345), "'script' must be passed as a single string. Got an object of class numeric instead.") + expect_error(run_script(client, c("I", "am", "a", "string")), "'script' must be passed as a single string. Got a string vector of length 4 instead.") - client$close() + close(client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 27ed2cb3ee8..362f4099c9f 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -27,17 +27,16 @@ setup <- function() { # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() # set up client - client_options <- ClientOptions$new() - client <- Client$new(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- client$import_table(df1) - th2 <- client$import_table(df2) - th3 <- client$import_table(df3) - th4 <- client$import_table(df4) + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) # time table to test is_static() - th5 <- client$time_table(1000000000) %>% update("X = ii") + th5 <- time_table(client, 1000000000) %>% update("X = ii") return(list( "client" = client, @@ -51,45 +50,46 @@ setup <- function() { test_that("is_static returns the correct value", { data <- setup() - expect_true(data$th1$is_static()) - expect_true(data$th2$is_static()) - expect_true(data$th3$is_static()) - expect_true(data$th4$is_static()) - expect_false(data$th5$is_static()) + expect_true(is_static(data$th1)) + expect_true(is_static(data$th2)) + expect_true(is_static(data$th3)) + expect_true(is_static(data$th4)) + expect_false(is_static(data$th5)) - data$client$close() + close(data$client) }) +# TODO: Implement so this doesn't fail test_that("nrow returns the correct number of rows", { data <- setup() - expect_equal(data$th1$nrow(), nrow(data$df1)) - expect_equal(data$th2$nrow(), nrow(data$df2)) - expect_equal(data$th3$nrow(), nrow(data$df3)) - expect_equal(data$th4$nrow(), nrow(data$df4)) + expect_equal(nrow(data$th1), nrow(data$df1)) + expect_equal(nrow(data$th2), nrow(data$df2)) + expect_equal(nrow(data$th3), nrow(data$df3)) + expect_equal(nrow(data$th4), nrow(data$df4)) - data$client$close() + close(data$client) }) test_that("bind_to_variable binds the table to a variable", { data <- setup() - data$th1$bind_to_variable("table1") - expect_no_error(data$client$open_table("table1")) + data$th1 %>% bind_to_variable("table1") + expect_no_error(open_table(data$client, "table1")) - data$th2$bind_to_variable("table2") - expect_no_error(data$client$open_table("table2")) + data$th2 %>% bind_to_variable("table2") + expect_no_error(open_table(data$client, "table2")) - data$th3$bind_to_variable("table3") - expect_no_error(data$client$open_table("table3")) + data$th3 %>% bind_to_variable("table3") + expect_no_error(open_table(data$client, "table3")) - data$th4$bind_to_variable("table4") - expect_no_error(data$client$open_table("table4")) + data$th4 %>% bind_to_variable("table4") + expect_no_error(open_table(data$client, "table4")) - data$client$close() + close(data$client) }) -test_that("to_arrow_record_batch_stream_reader returns an identical stream reader", { +test_that("to_record_batch_reader returns an identical stream reader", { data <- setup() # actual equality of RecordBatchStreamReaders is not expected, as they contain underlying pointers to relevant data, @@ -97,19 +97,19 @@ test_that("to_arrow_record_batch_stream_reader returns an identical stream reade # We care about equality in the sense that coercing to dataframes should yield identical dataframes, so we cast to dataframes and compare. # Additionally, as.data.frame() does not convert arrow tables to data frames, but to Tibbles. Need another as.data.frame to get a data frame. - rbr1 <- data$th1$to_arrow_record_batch_stream_reader() + rbr1 <- as_record_batch_reader(data$th1) expect_equal(as.data.frame(as.data.frame(rbr1$read_table())), data$df1) - rbr2 <- data$th2$to_arrow_record_batch_stream_reader() + rbr2 <- as_record_batch_reader(data$th2) expect_equal(as.data.frame(as.data.frame(rbr2$read_table())), data$df2) - rbr3 <- data$th3$to_arrow_record_batch_stream_reader() + rbr3 <- as_record_batch_reader(data$th3) expect_equal(as.data.frame(as.data.frame(rbr3$read_table())), data$df3) - rbr4 <- data$th4$to_arrow_record_batch_stream_reader() + rbr4 <- as_record_batch_reader(data$th4) expect_equal(as.data.frame(as.data.frame(rbr4$read_table())), data$df4) - data$client$close() + close(data$client) }) test_that("to_arrow_table returns a valid Arrow table", { @@ -118,88 +118,81 @@ test_that("to_arrow_table returns a valid Arrow table", { # The rationale for casting RecordBatchStreamReaders to dataframes for comparison also applies to Arrow Tables. # Additionally, as.data.frame() does not convert arrow tables to data frames, but to Tibbles. Need another as.data.frame to get a data frame. - arrow_tbl1 <- data$th1$to_arrow_table() + arrow_tbl1 <- as_arrow_table(data$th1) expect_equal(as.data.frame(as.data.frame(arrow_tbl1)), data$df1) - arrow_tbl2 <- data$th2$to_arrow_table() + arrow_tbl2 <- as_arrow_table(data$th2) expect_equal(as.data.frame(as.data.frame(arrow_tbl2)), data$df2) - arrow_tbl3 <- data$th3$to_arrow_table() + arrow_tbl3 <- as_arrow_table(data$th3) expect_equal(as.data.frame(as.data.frame(arrow_tbl3)), data$df3) - arrow_tbl4 <- data$th4$to_arrow_table() + arrow_tbl4 <- as_arrow_table(data$th4) expect_equal(as.data.frame(as.data.frame(arrow_tbl4)), data$df4) - data$client$close() + close(data$client) }) test_that("to_tibble returns a valid Tibble", { data <- setup() - tibble1 <- data$th1$to_tibble() + tibble1 <- as_tibble(data$th1) expect_equal(tibble1, as_tibble(data$df1)) - tibble2 <- data$th2$to_tibble() + tibble2 <- as_tibble(data$th2) expect_equal(tibble2, as_tibble(data$df2)) - tibble3 <- data$th3$to_tibble() + tibble3 <- as_tibble(data$th3) expect_equal(tibble3, as_tibble(data$df3)) - tibble4 <- data$th4$to_tibble() + tibble4 <- as_tibble(data$th4) expect_equal(tibble4, as_tibble(data$df4)) - data$client$close() + close(data$client) }) test_that("to_data_frame returns a valid data frame", { data <- setup() - data_frame1 <- data$th1$to_data_frame() + data_frame1 <- as.data.frame(data$th1) expect_equal(data_frame1, data$df1) - data_frame2 <- data$th2$to_data_frame() + data_frame2 <- as.data.frame(data$th2) expect_equal(data_frame2, data$df2) - data_frame3 <- data$th3$to_data_frame() + data_frame3 <- as.data.frame(data$th3) expect_equal(data_frame3, data$df3) - data_frame4 <- data$th4$to_data_frame() + data_frame4 <- as.data.frame(data$th4) expect_equal(data_frame4, data$df4) - data$client$close() + close(data$client) }) ##### TESTING BAD INPUTS ##### -test_that("trying to instantiate a TableHandle directly fails nicely", { - expect_error( - TableHandle$new("hello!"), - "'table_handle' should be an internal Deephaven TableHandle. If you're seeing this, you are trying to call the constructor of TableHandle directly, which is not advised." - ) -}) - test_that("bind_to_variable fails nicely on bad inputs", { data <- setup() expect_error( - data$th1$bind_to_variable(12345), + data$th1 %>% bind_to_variable(12345), "'name' must be passed as a single string. Got an object of class numeric instead." ) expect_error( - data$th1$bind_to_variable(c("multiple", "strings")), + data$th1 %>% bind_to_variable(c("multiple", "strings")), "'name' must be passed as a single string. Got a string vector of length 2 instead." ) expect_error( - data$th1$bind_to_variable(data$df1), + data$th1 %>% bind_to_variable(data$df1), "'name' must be passed as a single string. Got an object of class data.frame instead." ) expect_error( - data$th1$bind_to_variable(list("list", "of", "strings")), + data$th1 %>% bind_to_variable(list("list", "of", "strings")), "'name' must be passed as a single string. Got a string vector of length 3 instead." ) - data$client$close() + close(data$client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index bcbfd3182ed..dd6f475de39 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -1,6 +1,6 @@ +library(testthat) library(dplyr) library(rdeephaven) -library(testthat) setup <- function() { df1 <- data.frame( @@ -41,8 +41,7 @@ setup <- function() { # thus, we have to push these created tables to the server and get TableHandles to each of them. # set up client - client_options <- new("S4ClientOptions") - client <- connect(target = "localhost:10000", client_options = client_options) + client <- connect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing th1 <- import_table(client, df1) From 5203a1a5fed34c995b612703a50b5eadc53ac8f2 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 4 Aug 2023 23:28:46 -0500 Subject: [PATCH 44/73] Apply code review comments --- R/rdeephaven/R/new_aggregate_wrapper.R | 26 ++-- .../inst/tests/testthat/test_agg_by.R | 4 - .../testthat/test_table_handle_wrapper.R | 4 - .../inst/tests/testthat/test_table_ops.R | 5 +- R/rdeephaven/src/client.cpp | 121 ++++++------------ 5 files changed, 55 insertions(+), 105 deletions(-) diff --git a/R/rdeephaven/R/new_aggregate_wrapper.R b/R/rdeephaven/R/new_aggregate_wrapper.R index 3270cad84b3..d839a848bbe 100644 --- a/R/rdeephaven/R/new_aggregate_wrapper.R +++ b/R/rdeephaven/R/new_aggregate_wrapper.R @@ -11,79 +11,79 @@ setClass( #' @export agg_first <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_first(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_first(columns))) } #' @export agg_last <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_last(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_last(columns))) } #' @export agg_min <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_min(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_min(columns))) } #' @export agg_max <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_max(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_max(columns))) } #' @export agg_sum <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_sum(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_sum(columns))) } #' @export agg_abs_sum <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_abs_sum(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_abs_sum(columns))) } #' @export agg_avg <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_avg(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_avg(columns))) } #' @export agg_w_avg <- function(weight_column, columns = character()) { verify_string("weight_column", weight_column, TRUE) verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_w_avg(weight_column, columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_w_avg(weight_column, columns))) } #' @export agg_median <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_median(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_median(columns))) } #' @export agg_var <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_var(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_var(columns))) } #' @export agg_std <- function(columns = character()) { verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_std(columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_std(columns))) } #' @export agg_percentile <- function(percentile, columns = character()) { verify_in_unit_interval("percentile", percentile, TRUE) verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_percentile(percentile, columns))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_percentile(percentile, columns))) } #' @export agg_count <- function(count_column) { verify_string("count_column", count_column, TRUE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_count(count_column))) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_count(count_column))) } \ No newline at end of file diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index 7813b510816..79a4cb452cf 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -37,10 +37,6 @@ setup <- function() { Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) ) - # in order to test TableHandle, we need to have tables on the server that we know everything about. - # thus, we have to push these created tables to the server and get TableHandles to each of them. - # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() - # set up client client <- connect(target = "localhost:10000") diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 362f4099c9f..e762436be24 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -22,10 +22,6 @@ setup <- function() { int_col = sample(0:10000, 250000, TRUE) ) - # in order to test TableHandle, we need to have tables on the server that we know everything about. - # thus, we have to push these created tables to the server and get TableHandles to each of them. - # thus, we depend on the correctness of client$import_table(), ClientOptions$new(), and Client$new() - # set up client client <- connect(target = "localhost:10000") diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index dd6f475de39..7df77d16599 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -37,9 +37,6 @@ setup <- function() { Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) ) - # in order to test TableHandle, we need to have tables on the server that we know everything about. - # thus, we have to push these created tables to the server and get TableHandles to each of them. - # set up client client <- connect(target = "localhost:10000") @@ -258,7 +255,7 @@ test_that("where behaves as expected", { close(data$client) }) -test_that("group_by and ungroup behaves as expected", { +test_that("group_by and ungroup behave as expected", { data <- setup() # There is not a clean analog to group_by() in dplyr, so we evaluate diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 9053d30a54d..dd3476942d1 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -1,3 +1,9 @@ +/* + * Most of the methods here wrap methods defined in client.h and client_options.h to expose them to R via Rcpp. + * Thus, the only methods that are documented here are the ones that are unique to these classes, and not already + * documented in one of the header files mentioned above. + */ + #include #include #include @@ -38,7 +44,6 @@ class AggregateWrapper { friend std::vector convertRcppListToVectorOfTypeAggregate(Rcpp::List rcpp_list); }; -// ######################### conversion function for the above class std::vector convertRcppListToVectorOfTypeAggregate(Rcpp::List rcpp_list) { std::vector converted_list; converted_list.reserve(rcpp_list.size()); @@ -49,58 +54,59 @@ std::vector convertRcppListToVectorOfTypeAggregate deephaven::client::Aggregate internal_aggregation = xptr->internal_aggregation; converted_list.push_back(internal_aggregation); } + return converted_list; } -AggregateWrapper* INTERNAL_min(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_min(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::min(columnSpecs)); } -AggregateWrapper* INTERNAL_max(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_max(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::max(columnSpecs)); } -AggregateWrapper* INTERNAL_first(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_first(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::first(columnSpecs)); } -AggregateWrapper* INTERNAL_last(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_last(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::last(columnSpecs)); } -AggregateWrapper* INTERNAL_sum(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_sum(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::sum(columnSpecs)); } -AggregateWrapper* INTERNAL_absSum(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_absSum(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::absSum(columnSpecs)); } -AggregateWrapper* INTERNAL_avg(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_avg(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::avg(columnSpecs)); } -AggregateWrapper* INTERNAL_wAvg(std::string weightColumn, std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_wAvg(std::string weightColumn, std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::wavg(weightColumn, columnSpecs)); } -AggregateWrapper* INTERNAL_median(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_median(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::med(columnSpecs)); } -AggregateWrapper* INTERNAL_var(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_var(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::var(columnSpecs)); } -AggregateWrapper* INTERNAL_std(std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_std(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::std(columnSpecs)); } -AggregateWrapper* INTERNAL_percentile(double percentile, std::vector columnSpecs) { +AggregateWrapper* INTERNAL_agg_percentile(double percentile, std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::pct(percentile, false, columnSpecs)); } -AggregateWrapper* INTERNAL_count(std::string columnSpec) { +AggregateWrapper* INTERNAL_agg_count(std::string columnSpec) { return new AggregateWrapper(deephaven::client::Aggregate::count(columnSpec)); } @@ -110,10 +116,6 @@ class TableHandleWrapper { TableHandleWrapper(deephaven::client::TableHandle ref_table) : internal_tbl_hdl(std::move(ref_table)) {}; - // TABLE OPERATIONS - - // FILTER OPERATIONS - TableHandleWrapper* select(std::vector columnSpecs) { return new TableHandleWrapper(internal_tbl_hdl.select(columnSpecs)); }; @@ -146,8 +148,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.ungroup(false, groupByColumns)); }; - // AGGREGATION OPERATIONS - TableHandleWrapper* aggBy(Rcpp::List aggregations, std::vector groupByColumns) { std::vector converted_aggregations = convertRcppListToVectorOfTypeAggregate(aggregations); return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations), groupByColumns)); @@ -213,8 +213,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.countBy(countByColumn, columnSpecs)); }; - // JOIN OPERATIONS - TableHandleWrapper* crossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { return new TableHandleWrapper(internal_tbl_hdl.crossJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); }; @@ -227,8 +225,6 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.exactJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); }; - // MISC OPERATIONS - TableHandleWrapper* head(int64_t n) { return new TableHandleWrapper(internal_tbl_hdl.head(n)); }; @@ -245,8 +241,9 @@ class TableHandleWrapper { TableHandleWrapper* sort(std::vector columnSpecs, std::vector descending) { std::vector sort_pairs; sort_pairs.reserve(columnSpecs.size()); + if (descending.size() == 1) { - if (descending[0] == false) { + if (!descending[0]) { for(int i = 0; i < columnSpecs.size(); i++) { sort_pairs.push_back(deephaven::client::SortPair::ascending(columnSpecs[i], false)); } @@ -255,37 +252,29 @@ class TableHandleWrapper { sort_pairs.push_back(deephaven::client::SortPair::descending(columnSpecs[i], false)); } } - } else { + } + + else { for(int i = 0; i < columnSpecs.size(); i++) { - if (descending[i] == false) { + if (!descending[i]) { sort_pairs.push_back(deephaven::client::SortPair::ascending(columnSpecs[i], false)); } else { sort_pairs.push_back(deephaven::client::SortPair::descending(columnSpecs[i], false)); } } } + return new TableHandleWrapper(internal_tbl_hdl.sort(sort_pairs)); }; - /** - * Whether the table was static at the time internal_tbl_hdl was created. - */ bool isStatic() { return internal_tbl_hdl.isStatic(); } - /** - * Number of rows in the table at the time internal_tbl_hdl was created. - */ int64_t numRows() { return internal_tbl_hdl.numRows(); } - /** - * Binds the table referenced by this table handle to a variable on the server called tableName. - * Without this call, new tables are not accessible from the client. - * @param tableName Name for the new table on the server. - */ void bindToVariable(std::string tableName) { internal_tbl_hdl.bindToVariable(tableName); } @@ -314,7 +303,6 @@ class TableHandleWrapper { friend std::vector convertRcppListToVectorOfTypeTableHandle(Rcpp::List rcpp_list); }; -// ######################### conversion function for the above class std::vector convertRcppListToVectorOfTypeTableHandle(Rcpp::List rcpp_list) { std::vector converted_list; converted_list.reserve(rcpp_list.size()); @@ -325,11 +313,11 @@ std::vector convertRcppListToVectorOfTypeTableHa deephaven::client::TableHandle internal_tbl_hdl = xptr->internal_tbl_hdl; converted_list.push_back(internal_tbl_hdl); } + return converted_list; } -// TODO: Document this guy class ClientOptionsWrapper { public: @@ -384,37 +372,18 @@ class ClientWrapper { ClientWrapper(std::string target, const ClientOptionsWrapper &client_options) : internal_client(deephaven::client::Client::connect(target, *client_options.internal_options)) {} - /** - * Fetches a reference to a table named tableName on the server if it exists. - * @param tableName Name of the table to search for. - * @return TableHandle reference to the fetched table. - */ TableHandleWrapper* openTable(std::string tableName) { return new TableHandleWrapper(internal_tbl_hdl_mngr.fetchTable(tableName)); } - /** - * Creates a "zero-width" table on the server. Such a table knows its number of rows but has no columns. - * @param size Number of rows in the empty table. - */ TableHandleWrapper* emptyTable(int64_t size) { return new TableHandleWrapper(internal_tbl_hdl_mngr.emptyTable(size)); } - /** - * Creates a ticking table. - * @param startTimeNanos When the table should start ticking (in units of nanoseconds since the epoch). - * @param periodNanos Table ticking frequency (in nanoseconds). - * @return The TableHandle of the new table. - */ TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) { return new TableHandleWrapper(internal_tbl_hdl_mngr.timeTable(startTimeNanos, periodNanos)); }; - /** - * Runs a script on the server in the console language if a console was created. - * @param code String of the code to be executed on the server. - */ void runScript(std::string code) { internal_tbl_hdl_mngr.runScript(code); } @@ -481,14 +450,6 @@ class ClientWrapper { return new TableHandleWrapper(new_tbl_hdl); } - /** - * Shuts down the Client and all associated state (GRPC connections, subscriptions, etc). - * This method is used if a caller wants to shut down Client state early. If it is not called, - * the shutdown actions will happen when this Client is destructed. The caller must not use any - * associated data structures (TableHandleManager, TableHandle, etc) after close() is called or - * after Client's destructor is invoked. If the caller tries to do so, the behavior is - * unspecified. - */ void close() { internal_client.close(); } @@ -513,19 +474,19 @@ RCPP_MODULE(DeephavenInternalModule) { class_("INTERNAL_Aggregate") ; - function("INTERNAL_first", &INTERNAL_first); - function("INTERNAL_last", &INTERNAL_last); - function("INTERNAL_min", &INTERNAL_min); - function("INTERNAL_max", &INTERNAL_max); - function("INTERNAL_sum", &INTERNAL_sum); - function("INTERNAL_abs_sum", &INTERNAL_absSum); - function("INTERNAL_avg", &INTERNAL_avg); - function("INTERNAL_w_avg", &INTERNAL_wAvg); - function("INTERNAL_median", &INTERNAL_median); - function("INTERNAL_var", &INTERNAL_var); - function("INTERNAL_std", &INTERNAL_std); - function("INTERNAL_percentile", &INTERNAL_percentile); - function("INTERNAL_count", &INTERNAL_count); + function("INTERNAL_agg_first", &INTERNAL_agg_first); + function("INTERNAL_agg_last", &INTERNAL_agg_last); + function("INTERNAL_agg_min", &INTERNAL_agg_min); + function("INTERNAL_agg_max", &INTERNAL_agg_max); + function("INTERNAL_agg_sum", &INTERNAL_agg_sum); + function("INTERNAL_agg_abs_sum", &INTERNAL_agg_absSum); + function("INTERNAL_agg_avg", &INTERNAL_agg_avg); + function("INTERNAL_agg_w_avg", &INTERNAL_agg_wAvg); + function("INTERNAL_agg_median", &INTERNAL_agg_median); + function("INTERNAL_agg_var", &INTERNAL_agg_var); + function("INTERNAL_agg_std", &INTERNAL_agg_std); + function("INTERNAL_agg_percentile", &INTERNAL_agg_percentile); + function("INTERNAL_agg_count", &INTERNAL_agg_count); class_("INTERNAL_TableHandle") .method("select", &TableHandleWrapper::select) From 4f09a712d339605aadd866ded1fd10764184c236 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 7 Aug 2023 18:03:52 -0500 Subject: [PATCH 45/73] Implement merge --- R/rdeephaven/NAMESPACE | 2 + ...ggregate_wrapper.R => aggregate_wrapper.R} | 2 +- ...{new_client_wrapper.R => client_wrapper.R} | 99 ++++++--------- R/rdeephaven/R/exports.R | 2 +- R/rdeephaven/R/helper_functions.R | 49 +++----- ...andle_wrapper.R => table_handle_wrapper.R} | 4 +- .../R/{new_table_ops.R => table_ops.R} | 115 +++++++++++++++++- .../inst/tests/testthat/test_client_wrapper.R | 46 ++++++- .../inst/tests/testthat/test_table_ops.R | 44 +++++++ 9 files changed, 263 insertions(+), 100 deletions(-) rename R/rdeephaven/R/{new_aggregate_wrapper.R => aggregate_wrapper.R} (99%) rename R/rdeephaven/R/{new_client_wrapper.R => client_wrapper.R} (81%) rename R/rdeephaven/R/{new_table_handle_wrapper.R => table_handle_wrapper.R} (98%) rename R/rdeephaven/R/{new_table_ops.R => table_ops.R} (86%) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index a275eb55fbb..22e18a09f9b 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -13,6 +13,7 @@ export(agg_std) export(agg_sum) export(agg_var) export(agg_w_avg) +export(merge) export(sort) exportClasses(Aggregation) exportClasses(Client) @@ -41,6 +42,7 @@ exportMethods(is_static) exportMethods(last_by) exportMethods(max_by) exportMethods(median_by) +exportMethods(merge) exportMethods(min_by) exportMethods(natural_join) exportMethods(nrow) diff --git a/R/rdeephaven/R/new_aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R similarity index 99% rename from R/rdeephaven/R/new_aggregate_wrapper.R rename to R/rdeephaven/R/aggregate_wrapper.R index d839a848bbe..63e6662fe02 100644 --- a/R/rdeephaven/R/new_aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -86,4 +86,4 @@ agg_percentile <- function(percentile, columns = character()) { agg_count <- function(count_column) { verify_string("count_column", count_column, TRUE) return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_count(count_column))) -} \ No newline at end of file +} diff --git a/R/rdeephaven/R/new_client_wrapper.R b/R/rdeephaven/R/client_wrapper.R similarity index 81% rename from R/rdeephaven/R/new_client_wrapper.R rename to R/rdeephaven/R/client_wrapper.R index 5dd38045a0d..c1e422ea8af 100644 --- a/R/rdeephaven/R/new_client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -27,70 +27,69 @@ setMethod( int_option = "", string_option = "", extra_header = "") { - options <- new(INTERNAL_ClientOptions) # check if auth_type needs to be changed and set credentials accordingly - if(auth_type != "anonymous") { - if(auth_type == "basic") { - if(auth_token_pair != "") { + if (auth_type != "anonymous") { + if (auth_type == "basic") { + if (auth_token_pair != "") { + verify_string("auth_token_pair", auth_token_pair, TRUE) username_password <- strsplit(auth_token_pair, ":", fixed = TRUE) options$set_basic_authentication(username_password[1], username_password[2]) - } - else { + } else { stop("Basic authentication was requested, but no 'auth_token_pair' was provided.") } - } - else if(auth_type == "custom") { - if(auth_token_pair != "") { + } else if (auth_type == "custom") { + if (auth_token_pair != "") { + verify_string("auth_token_pair", auth_token_pair, TRUE) key_value <- strsplit(auth_token_pair, ":", fixed = TRUE) options$set_custom_authentication(key_value[1], key_value[2]) - } - else { + } else { stop("Custom authentication was requested, but no 'auth_token_pair' was provided.") } - } - else { + } else { stop(paste0("'auth_type' must be 'anonymous', 'basic', or 'custom', but got ", auth_type, " instead.")) } } - + # set session type if a valid session type is provided - if((session_type == "python") || (session_type == "groovy")) { + if ((session_type == "python") || (session_type == "groovy")) { options$set_session_type(session_type) - } - else { + } else { stop(paste0("'session_type' must be 'python' or 'groovy', but got ", session_type, " instead.")) } - + # if tls is requested, set it and set the root_certs if provided - if(use_tls != FALSE) { - if(use_tls == TRUE) { + if (use_tls != FALSE) { + if (use_tls == TRUE) { options$set_use_tls() - if(tls_root_certs != "") { + if (tls_root_certs != "") { + verify_string("tls_root_certs", tls_root_certs, TRUE) options$set_tls_root_certs(tls_root_certs) } - } - else { + } else { stop(paste0("'use_tls' must be TRUE or FALSE, but got ", use_tls, " instead.")) } } - - if(int_option != "") { + + if (int_option != "") { + verify_string("int_option", int_option, TRUE) new_int_option <- strsplit(int_option, ":", fixed = TRUE) options$add_int_option(new_int_option[1], as.numeric(new_int_option[2])) } - - if(string_option != "") { + + if (string_option != "") { + verify_string("string_option", string_option, TRUE) new_string_option <- strsplit(string_option, ":", fixed = TRUE) options$add_string_option(new_string_option[1], new_string_option[2]) } - - if(extra_header != "") { + + if (extra_header != "") { + verify_string("extra_header", extra_header, TRUE) new_extra_header <- strsplit(extra_header, ":", fixed = TRUE) options$add_extra_header(new_extra_header[1], new_extra_header[2]) } - + internal_client <- new(INTERNAL_Client, target = target, client_options = options @@ -99,27 +98,6 @@ setMethod( } ) -#' setGeneric( -#' "connect", -#' function(target, client_options) { -#' return(standardGeneric("connect")) -#' }, -#' signature = c("target", "client_options") -#' ) -#' -#' #' @export -#' setMethod( -#' "connect", -#' signature = c(target = "character", client_options = "ClientOptions"), -#' function(target, client_options) { -#' internal_client <- new(INTERNAL_Client, -#' target = target, -#' client_options = client_options@.internal_rcpp_object -#' ) -#' return(new("Client", .internal_rcpp_object = internal_client)) -#' } -#' ) - ### HELPER FUNCTIONS ### # These functions return RC objects returned by Rcpp without wrapping them in S4 @@ -221,24 +199,19 @@ setMethod( "import_table", signature = c(client_instance = "Client"), function(client_instance, table_object) { - table_object_class <- class(table_object) - + if (table_object_class[[1]] == "data.frame") { rcpp_dh_table <- df_to_dh_table(client_instance, table_object) - } - else if (table_object_class[[1]] == "tbl_df") { + } else if (table_object_class[[1]] == "tbl_df") { rcpp_dh_table <- tibble_to_dh_table(client_instance, table_object) - } - else if (table_object_class[[1]] == "RecordBatchReader") { + } else if (table_object_class[[1]] == "RecordBatchReader") { rcpp_dh_table <- rbr_to_dh_table(client_instance, table_object) - } - else if ((length(table_object_class) == 4 && - table_object_class[[1]] == "Table" && - table_object_class[[3]] == "ArrowObject")) { + } else if ((length(table_object_class) == 4 && + table_object_class[[1]] == "Table" && + table_object_class[[3]] == "ArrowObject")) { rcpp_dh_table <- arrow_to_dh_table(client_instance, table_object) - } - else { + } else { stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], " instead.")) } return(new("TableHandle", .internal_rcpp_object = rcpp_dh_table)) diff --git a/R/rdeephaven/R/exports.R b/R/rdeephaven/R/exports.R index 3573cf37784..4797e402113 100644 --- a/R/rdeephaven/R/exports.R +++ b/R/rdeephaven/R/exports.R @@ -1,7 +1,7 @@ #' @import Rcpp #' @useDynLib rdeephaven, .registration = TRUE #' @importFrom Rcpp evalCpp -#' +#' #' @importFrom magrittr %>% #' @importFrom arrow arrow_table as_arrow_table as_record_batch_reader RecordBatchStreamReader #' @importFrom dplyr as_tibble diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index a743f4ee852..4fc75f8e4e2 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -1,23 +1,24 @@ -first_class <- function(arg) { return(class(arg)[[1]]) } +first_class <- function(arg) { + return(class(arg)[[1]]) +} verify_type <- function(arg_name, candidate, required_type, message_type_name, is_scalar) { - if(first_class(candidate) == "list") { - if(any(lapply(candidate, first_class) != required_type)) { + if (first_class(candidate) == "list") { + if (any(lapply(candidate, first_class) != required_type)) { stop(paste0("'", arg_name, "' must be a ", message_type_name, ", or a vector of ", message_type_name, "s. Got a vector with at least one element that is not a ", message_type_name, " instead.")) } - } - else { - if(first_class(candidate) != required_type) { - if(is_scalar) { + } else { + if (first_class(candidate) != required_type) { + if (is_scalar) { stop(paste0("'", arg_name, "' must be passed as a single ", message_type_name, ". Got an object of class ", first_class(candidate), " instead.")) - } - else { + } else { stop(paste0("'", arg_name, "' must be passed as a ", message_type_name, " or a vector of ", message_type_name, "s. Got an object of class ", first_class(candidate), " instead.")) } } } - if(is_scalar) { - if(length(candidate) != 1) { + + if (is_scalar) { + if (length(candidate) != 1) { stop(paste0("'", arg_name, "' must be passed as a single ", message_type_name, ". Got a ", message_type_name, " vector of length ", length(candidate), " instead.")) } } @@ -25,14 +26,11 @@ verify_type <- function(arg_name, candidate, required_type, message_type_name, i # does not attempt to verify that candidate is numeric verify_in_range <- function(arg_name, candidate, message, a = NULL, b = NULL, a_open = TRUE, b_open = TRUE) { - - if(((!is.null(a)) && ((any(candidate <= a) && (a_open)) || (any(candidate < a) && (!a_open)))) || - ((!is.null(b)) && ((any(candidate >= b) && (b_open)) || (any(candidate > b) && (!b_open))))) { - - if(length(candidate) == 1) { + if (((!is.null(a)) && ((any(candidate <= a) && (a_open)) || (any(candidate < a) && (!a_open)))) || + ((!is.null(b)) && ((any(candidate >= b) && (b_open)) || (any(candidate > b) && (!b_open))))) { + if (length(candidate) == 1) { stop(paste0("'", arg_name, "' must be ", message, ". Got '", arg_name, "' = ", candidate, " instead.")) - } - else { + } else { stop(paste0("Every element of '", arg_name, "' must be ", message, ". Got at least one element that is not ", message, " instead.")) } } @@ -40,11 +38,10 @@ verify_in_range <- function(arg_name, candidate, message, a = NULL, b = NULL, a_ # does not attempt to verify that candidate is numeric verify_int <- function(arg_name, candidate) { - if(candidate != as.integer(candidate)) { - if(length(candidate == 1)) { + if (candidate != as.integer(candidate)) { + if (length(candidate == 1)) { stop(paste0("'", arg_name, "' must be an integer. Got '", arg_name, "' = ", candidate, " instead.")) - } - else { + } else { stop(paste0("Every element of '", arg_name, "' must be an integer. Got at least one non-integer element instead.")) } } @@ -84,14 +81,6 @@ verify_positive_int <- function(arg_name, candidate, is_scalar) { verify_in_range(arg_name, candidate, message = "a positive integer", a = 0) } -strip_r6_wrapping_from_aggregation <- function(r6_aggregation) { - return(r6_aggregation$internal_aggregation) -} - -strip_r6_wrapping_from_table_handle <- function(r6_table_handle) { - return(r6_table_handle$internal_table_handle) -} - strip_s4_wrapping <- function(s4_object) { return(s4_object@.internal_rcpp_object) } diff --git a/R/rdeephaven/R/new_table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R similarity index 98% rename from R/rdeephaven/R/new_table_handle_wrapper.R rename to R/rdeephaven/R/table_handle_wrapper.R index b6e83fac08f..66b81dab20b 100644 --- a/R/rdeephaven/R/new_table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -54,7 +54,7 @@ setMethod( } ) -# TODO: Implement nrow, ncol, dim +# TODO: Implement ncol, dim ### TABLEHANDLE CONVERSIONS ### @@ -120,4 +120,4 @@ setMethod( table_handle_instance@.internal_rcpp_object$bind_to_variable(name) return(NULL) } -) \ No newline at end of file +) diff --git a/R/rdeephaven/R/new_table_ops.R b/R/rdeephaven/R/table_ops.R similarity index 86% rename from R/rdeephaven/R/new_table_ops.R rename to R/rdeephaven/R/table_ops.R index d160cc484f5..0761c0d61a1 100644 --- a/R/rdeephaven/R/new_table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -1,3 +1,117 @@ +setGeneric( + "merge", + function(x, y = NULL, ...) { + standardGeneric("merge") + } +) + +# We need many implementations of 'merge' because of the kind of args it should support + +base_merge <- function(x, y, ...) { + arg_list <- c(unlist(x), unlist(y), unlist(c(...))) + if (length(arg_list) == 1) { + return(arg_list[[1]]) + } + unwrapped_arg_list <- lapply(arg_list, strip_s4_wrapping) + return(new("TableHandle", .internal_rcpp_object = unwrapped_arg_list[[1]]$merge(unwrapped_arg_list[2:length(unwrapped_arg_list)]))) +} + +#' @export +setMethod( + "merge", + signature = c(x = "TableHandle"), + function(x, y = NULL, ...) { + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "list"), + function(x, y = NULL, ...) { + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "TableHandle", y = "list"), + function(x, y, ...) { + verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "list", y = "TableHandle"), + function(x, y, ...) { + verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "TableHandle", y = "TableHandle"), + function(x, y, ...) { + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "list", y = "list"), + function(x, y, ...) { + verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) + verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "NULL", y = "TableHandle"), + function(x, y, ...) { + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "NULL", y = "list"), + function(x, y, ...) { + verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "TableHandle", y = "NULL"), + function(x, y, ...) { + return(base_merge(x, y, c(...))) + } +) + +#' @export +setMethod( + "merge", + signature = c(x = "list", y = "NULL"), + function(x, y, ...) { + verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) + return(base_merge(x, y, c(...))) + } +) + setGeneric( "select", function(table_handle, columns = character(), ...) { @@ -526,4 +640,3 @@ setMethod( return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(columns, descending))) } ) - diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 871bc9248a6..8ac364ef378 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -150,8 +150,50 @@ int_col("Name_Int_Col", [44, 55, 66]) ##### TESTING BAD INPUTS ##### -# FAILS -# TODO: Test all of the new client connections stuff +test_that("connect fails nicely with bad inputs", { + + expect_error( + connect(target = "localhost:10000", auth_type = "basic"), + "Basic authentication was requested, but no 'auth_token_pair' was provided." + ) + expect_error( + connect(target = "localhost:10000", auth_type = "custom"), + "Custom authentication was requested, but no 'auth_token_pair' was provided." + ) + expect_error( + connect(target = "localhost:10000", auth_type = "blahblah"), + "'auth_type' must be 'anonymous', 'basic', or 'custom', but got blahblah instead." + ) + expect_error( + connect(target = "localhost:10000", auth_type = "basic", auth_token_pair = 1234), + "'auth_token_pair' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + connect(target = "localhost:10000", session_type = "blahblah"), + "'session_type' must be 'python' or 'groovy', but got blahblah instead." + ) + expect_error( + connect(target = "localhost:10000", session_type = 1234), + "'session_type' must be 'python' or 'groovy', but got 1234 instead." + ) + expect_error( + connect(target = "localhost:10000", use_tls = "banana"), + "'use_tls' must be TRUE or FALSE, but got banana instead." + ) + expect_error( + connect(target = "localhost:10000", int_option = 1234), + "'int_option' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + connect(target = "localhost:10000", string_option = 1234), + "'string_option' must be passed as a single string. Got an object of class numeric instead." + ) + expect_error( + connect(target = "localhost:10000", extra_header = 1234), + "'extra_header' must be passed as a single string. Got an object of class numeric instead." + ) + +}) test_that("import_table fails nicely with bad inputs", { library(datasets) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 7df77d16599..13fa7be38b2 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -57,6 +57,50 @@ setup <- function() { ##### TESTING GOOD INPUTS ##### +test_that("merge behaves as expected", { + data <- setup() + + new_df1 <- rbind(data$df5) + new_th1 <- merge(data$th5) + expect_equal(as.data.frame(new_th1), new_df1) + + new_df2 <- rbind(data$df5, data$df6) + new_th2 <- merge(data$th5, data$th6) + expect_equal(as.data.frame(new_th2), new_df2) + + new_df3 <- rbind(data$df5, data$df6, data$df6, data$df5) + new_th3 <- merge(data$th5, data$th6, data$th6, data$th5) + expect_equal(as.data.frame(new_th3), new_df3) + + new_th4 <- merge(data$th5, NULL) + expect_equal(as.data.frame(new_th4), new_df1) + + new_th5 <- merge(NULL, data$th5) + expect_equal(as.data.frame(new_th5), new_df1) + + new_th6 <- merge(c(data$th5, data$th6)) + expect_equal(as.data.frame(new_th6), new_df2) + + new_th7 <- merge(NULL, c(data$th5, data$th6)) + expect_equal(as.data.frame(new_th7), new_df2) + + new_th8 <- merge(c(data$th5, data$th6), NULL) + expect_equal(as.data.frame(new_th8), new_df2) + + new_th9 <- merge(data$th5, c(data$th6, data$th6, data$th5)) + expect_equal(as.data.frame(new_th9), new_df3) + + new_th10 <- merge(c(data$th5, data$th6, data$th6), data$th5) + expect_equal(as.data.frame(new_th10), new_df3) + + new_th11 <- merge(c(data$th5, data$th6), c(data$th6, data$th5)) + expect_equal(as.data.frame(new_th11), new_df3) + + new_th12 <- merge(c(data$th5, data$th6, data$th6, data$th5)) + expect_equal(as.data.frame(new_th12), new_df3) + +}) + test_that("select behaves as expected", { data <- setup() From 826aaa5bd4bfffa446dcd34c3f9c922322ba2224 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 7 Aug 2023 18:10:34 -0500 Subject: [PATCH 46/73] Code review change --- R/rdeephaven/src/client.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index dd3476942d1..9fb1b69b802 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -471,7 +471,6 @@ RCPP_EXPOSED_CLASS(SortPairWrapper) RCPP_EXPOSED_CLASS(ArrowArrayStream) RCPP_MODULE(DeephavenInternalModule) { - class_("INTERNAL_Aggregate") ; function("INTERNAL_agg_first", &INTERNAL_agg_first); From e2dde0c72de9d65a237c61f4f120222ce5aa80b9 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 7 Aug 2023 18:12:04 -0500 Subject: [PATCH 47/73] Cpp formatting --- R/rdeephaven/src/client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 9fb1b69b802..fc827547742 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -487,6 +487,7 @@ RCPP_MODULE(DeephavenInternalModule) { function("INTERNAL_agg_percentile", &INTERNAL_agg_percentile); function("INTERNAL_agg_count", &INTERNAL_agg_count); + class_("INTERNAL_TableHandle") .method("select", &TableHandleWrapper::select) .method("view", &TableHandleWrapper::view) From 433e78735092e9ee9d1261f46c464fe2cb7a0a43 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 7 Aug 2023 19:01:52 -0500 Subject: [PATCH 48/73] Test base pipe --- R/rdeephaven/R/aggregate_wrapper.R | 80 +- R/rdeephaven/R/client_wrapper.R | 8 +- R/rdeephaven/R/table_ops.R | 268 +++--- .../tests/testthat/test_agg_by_base_pipe.R | 743 ++++++++++++++++ ...t_agg_by.R => test_agg_by_magrittr_pipe.R} | 0 .../tests/testthat/test_aggregate_wrapper.R | 88 +- .../inst/tests/testthat/test_client_wrapper.R | 50 +- .../tests/testthat/test_table_ops_base_pipe.R | 840 ++++++++++++++++++ ...e_ops.R => test_table_ops_magrittr_pipe.R} | 0 9 files changed, 1847 insertions(+), 230 deletions(-) create mode 100644 R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R rename R/rdeephaven/inst/tests/testthat/{test_agg_by.R => test_agg_by_magrittr_pipe.R} (100%) create mode 100644 R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R rename R/rdeephaven/inst/tests/testthat/{test_table_ops.R => test_table_ops_magrittr_pipe.R} (100%) diff --git a/R/rdeephaven/R/aggregate_wrapper.R b/R/rdeephaven/R/aggregate_wrapper.R index 63e6662fe02..600e278c49d 100644 --- a/R/rdeephaven/R/aggregate_wrapper.R +++ b/R/rdeephaven/R/aggregate_wrapper.R @@ -9,81 +9,81 @@ setClass( ### All of the functions below return an instance of the above class #' @export -agg_first <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_first(columns))) +agg_first <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_first(cols))) } #' @export -agg_last <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_last(columns))) +agg_last <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_last(cols))) } #' @export -agg_min <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_min(columns))) +agg_min <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_min(cols))) } #' @export -agg_max <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_max(columns))) +agg_max <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_max(cols))) } #' @export -agg_sum <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_sum(columns))) +agg_sum <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_sum(cols))) } #' @export -agg_abs_sum <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_abs_sum(columns))) +agg_abs_sum <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_abs_sum(cols))) } #' @export -agg_avg <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_avg(columns))) +agg_avg <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_avg(cols))) } #' @export -agg_w_avg <- function(weight_column, columns = character()) { - verify_string("weight_column", weight_column, TRUE) - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_w_avg(weight_column, columns))) +agg_w_avg <- function(wcol, cols = character()) { + verify_string("wcol", wcol, TRUE) + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_w_avg(wcol, cols))) } #' @export -agg_median <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_median(columns))) +agg_median <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_median(cols))) } #' @export -agg_var <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_var(columns))) +agg_var <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_var(cols))) } #' @export -agg_std <- function(columns = character()) { - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_std(columns))) +agg_std <- function(cols = character()) { + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_std(cols))) } #' @export -agg_percentile <- function(percentile, columns = character()) { +agg_percentile <- function(percentile, cols = character()) { verify_in_unit_interval("percentile", percentile, TRUE) - verify_string("columns", columns, FALSE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_percentile(percentile, columns))) + verify_string("cols", cols, FALSE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_percentile(percentile, cols))) } #' @export -agg_count <- function(count_column) { - verify_string("count_column", count_column, TRUE) - return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_count(count_column))) +agg_count <- function(col) { + verify_string("col", col, TRUE) + return(new("Aggregation", .internal_rcpp_object = INTERNAL_agg_count(col))) } diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index c1e422ea8af..0a29ed24211 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -179,10 +179,10 @@ setGeneric( setMethod( "time_table", signature = c(client_instance = "Client"), - function(client_instance, period_nanos, start_time_nanos = 0) { - verify_any_int("period_nanos", period_nanos, TRUE) - verify_any_int("start_time_nanos", start_time_nanos, TRUE) - return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$time_table(start_time_nanos, period_nanos))) + function(client_instance, period, start_time = 0) { + verify_any_int("period", period, TRUE) + verify_any_int("start_time", start_time, TRUE) + return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$time_table(start_time, period))) } ) diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 0761c0d61a1..07e6e734087 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -114,441 +114,441 @@ setMethod( setGeneric( "select", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { return(standardGeneric("select")) }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "select", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$select(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$select(by))) } ) setGeneric( "view", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { return(standardGeneric("view")) }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "view", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$view(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$view(by))) } ) setGeneric( "update", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("update") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "update", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update(by))) } ) setGeneric( "update_view", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("update_view") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "update_view", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update_view(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$update_view(by))) } ) setGeneric( "drop_columns", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("drop_columns") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "drop_columns", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$drop_columns(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$drop_columns(by))) } ) setGeneric( "where", - function(table_handle, condition, ...) { + function(table_handle, filter, ...) { standardGeneric("where") }, - signature = c("table_handle", "condition") + signature = c("table_handle", "filter") ) #' @export setMethod( "where", signature = c(table_handle = "TableHandle"), - function(table_handle, condition) { - verify_string("condition", condition, TRUE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$where(condition))) + function(table_handle, filter) { + verify_string("filter", filter, TRUE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$where(filter))) } ) setGeneric( "group_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("group_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "group_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$group_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$group_by(by))) } ) setGeneric( "ungroup", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("ungroup") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "ungroup", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$ungroup(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$ungroup(by))) } ) setGeneric( "agg_by", - function(table_handle, aggregations, columns = character(), ...) { + function(table_handle, aggs, by = character(), ...) { standardGeneric("agg_by") }, - signature = c("table_handle", "aggregations", "columns") + signature = c("table_handle", "aggs", "by") ) #' @export setMethod( "agg_by", signature = c(table_handle = "TableHandle"), - function(table_handle, aggregations, columns = character()) { - verify_type("aggregations", aggregations, "Aggregation", "Deephaven Aggregation", FALSE) - verify_string("columns", columns, FALSE) - aggregations <- c(aggregations) - unwrapped_aggregations <- lapply(aggregations, strip_s4_wrapping) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$agg_by(unwrapped_aggregations, columns))) + function(table_handle, aggs, by = character()) { + verify_type("aggs", aggs, "Aggregation", "Deephaven Aggregation", FALSE) + verify_string("by", by, FALSE) + aggs <- c(aggs) + unwrapped_aggs <- lapply(aggs, strip_s4_wrapping) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$agg_by(unwrapped_aggs, by))) } ) setGeneric( "first_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("first_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "first_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$first_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$first_by(by))) } ) setGeneric( "last_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("last_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "last_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$last_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$last_by(by))) } ) setGeneric( "head_by", - function(table_handle, n, columns = character(), ...) { + function(table_handle, num_rows, by = character(), ...) { standardGeneric("head_by") }, - signature = c("table_handle", "n", "columns") + signature = c("table_handle", "num_rows", "by") ) #' @export setMethod( "head_by", signature = c(table_handle = "TableHandle"), - function(table_handle, n, columns = character()) { - verify_positive_int("n", n, TRUE) - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$head_by(n, columns))) + function(table_handle, num_rows, by = character()) { + verify_positive_int("num_rows", num_rows, TRUE) + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$head_by(num_rows, by))) } ) setGeneric( "tail_by", - function(table_handle, n, columns = character(), ...) { + function(table_handle, num_rows, by = character(), ...) { standardGeneric("tail_by") }, - signature = c("table_handle", "n", "columns") + signature = c("table_handle", "num_rows", "by") ) #' @export setMethod( "tail_by", signature = c(table_handle = "TableHandle"), - function(table_handle, n, columns = character()) { - verify_positive_int("n", n, TRUE) - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$tail_by(n, columns))) + function(table_handle, num_rows, by = character()) { + verify_positive_int("num_rows", num_rows, TRUE) + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$tail_by(num_rows, by))) } ) setGeneric( "min_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("min_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "min_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$min_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$min_by(by))) } ) setGeneric( "max_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("max_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "max_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$max_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$max_by(by))) } ) setGeneric( "sum_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("sum_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "sum_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sum_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sum_by(by))) } ) setGeneric( "abs_sum_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("abs_sum_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "abs_sum_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$abs_sum_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$abs_sum_by(by))) } ) setGeneric( "avg_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("avg_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "avg_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$avg_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$avg_by(by))) } ) setGeneric( "w_avg_by", - function(table_handle, weight_column, columns = character(), ...) { + function(table_handle, wcol, by = character(), ...) { standardGeneric("w_avg_by") }, - signature = c("table_handle", "weight_column", "columns") + signature = c("table_handle", "wcol", "by") ) #' @export setMethod( "w_avg_by", signature = c(table_handle = "TableHandle"), - function(table_handle, weight_column, columns = character()) { - verify_string("weight_column", weight_column, TRUE) - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$w_avg_by(weight_column, columns))) + function(table_handle, wcol, by = character()) { + verify_string("wcol", wcol, TRUE) + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$w_avg_by(wcol, by))) } ) setGeneric( "median_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("median_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "median_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$median_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$median_by(by))) } ) setGeneric( "var_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("var_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "var_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$var_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$var_by(by))) } ) setGeneric( "std_by", - function(table_handle, columns = character(), ...) { + function(table_handle, by = character(), ...) { standardGeneric("std_by") }, - signature = c("table_handle", "columns") + signature = c("table_handle", "by") ) #' @export setMethod( "std_by", signature = c(table_handle = "TableHandle"), - function(table_handle, columns = character()) { - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$std_by(columns))) + function(table_handle, by = character()) { + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$std_by(by))) } ) setGeneric( "percentile_by", - function(table_handle, percentile, columns = character(), ...) { + function(table_handle, percentile, by = character(), ...) { standardGeneric("percentile_by") }, - signature = c("table_handle", "percentile", "columns") + signature = c("table_handle", "percentile", "by") ) #' @export setMethod( "percentile_by", signature = c(table_handle = "TableHandle"), - function(table_handle, percentile, columns = character()) { + function(table_handle, percentile, by = character()) { verify_in_unit_interval("percentile", percentile, TRUE) - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$percentile_by(percentile, columns))) + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$percentile_by(percentile, by))) } ) setGeneric( "count_by", - function(table_handle, count_by_column, columns = character(), ...) { + function(table_handle, col, by = character(), ...) { standardGeneric("count_by") }, - signature = c("table_handle", "count_by_column", "columns") + signature = c("table_handle", "col", "by") ) #' @export setMethod( "count_by", signature = c(table_handle = "TableHandle"), - function(table_handle, count_by_column = "n", columns = character()) { - verify_string("count_by_column", count_by_column, TRUE) - verify_string("columns", columns, FALSE) - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$count_by(count_by_column, columns))) + function(table_handle, col = "n", by = character()) { + verify_string("col", col, TRUE) + verify_string("by", by, FALSE) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$count_by(col, by))) } ) @@ -621,22 +621,22 @@ setMethod( #' @export setGeneric( "sort", - function(table_handle, columns = character(), descending = FALSE, ...) { + function(table_handle, by = character(), descending = FALSE, ...) { standardGeneric("sort") }, - signature = c("table_handle", "columns", "descending") + signature = c("table_handle", "by", "descending") ) #' @export setMethod( "sort", signature = c(table_handle = "TableHandle"), - function(table_handle, columns, descending = FALSE) { - verify_string("columns", columns, FALSE) + function(table_handle, by, descending = FALSE) { + verify_string("by", by, FALSE) verify_bool("descending", descending, FALSE) - if ((length(descending) > 1) && length(descending) != length(columns)) { - stop(paste0("'descending' must be the same length as 'columns' if more than one entry is supplied. Got 'columns' with length ", length(columns), " and 'descending' with length", length(descending), " instead.")) + if ((length(descending) > 1) && length(descending) != length(by)) { + stop(paste0("'descending' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'descending' with length", length(descending), " instead.")) } - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(columns, descending))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(by, descending))) } ) diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R b/R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R new file mode 100644 index 00000000000..580ea51a6c2 --- /dev/null +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R @@ -0,0 +1,743 @@ +library(testthat) +library(dplyr) +library(rdeephaven) + +setup <- function() { + df1 <- data.frame( + string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) + ) + + df2 <- data.frame( + col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100) + ) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame( + time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE) + ) + + df5 <- data.frame( + X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), + Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), + Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214) + ) + + df6 <- data.frame( + X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), + Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), + Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), + Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) + ) + + # set up client + client <- connect(target = "localhost:10000") + + # move dataframes to server and get TableHandles for testing + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) + th5 <- import_table(client, df5) + th6 <- import_table(client, df6) + + return(list( + "client" = client, + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6 + )) +} + +test_that("agg_first behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = first(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_first("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = first(col3)) + new_th2 <- data$th2 |> + agg_by(agg_first("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = first(X5), X6 = first(X6), X7 = first(X7), X8 = first(X8)) + new_th3 <- data$th3 |> + agg_by(agg_first(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(time_col = first(time_col), int_col = first(int_col)) + new_th4 <- data$th4 |> + agg_by(c(agg_first("time_col"), agg_first("int_col")), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = first(Number1), Number2 = first(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_first(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = first(Number1), Number2 = first(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_first(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_last behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = last(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_last("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = last(col3)) + new_th2 <- data$th2 |> + agg_by(agg_last("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = last(X5), X6 = last(X6), X7 = last(X7), X8 = last(X8)) + new_th3 <- data$th3 |> + agg_by(agg_last(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(time_col = last(time_col), int_col = last(int_col)) + new_th4 <- data$th4 |> + agg_by(c(agg_last("time_col"), agg_last("int_col")), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = last(Number1), Number2 = last(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_last(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = last(Number1), Number2 = last(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_last(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_min behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = min(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_min("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = min(col3)) + new_th2 <- data$th2 |> + agg_by(agg_min("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = min(X5), X6 = min(X6), X7 = min(X7), X8 = min(X8)) + new_th3 <- data$th3 |> + agg_by(agg_min(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(time_col = min(time_col), int_col = min(int_col)) + new_th4 <- data$th4 |> + agg_by(c(agg_min("time_col"), agg_min("int_col")), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = min(Number1), Number2 = min(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_min(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = min(Number1), Number2 = min(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_min(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_max behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = max(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_max("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = max(col3)) + new_th2 <- data$th2 |> + agg_by(agg_max("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = max(X5), X6 = max(X6), X7 = max(X7), X8 = max(X8)) + new_th3 <- data$th3 |> + agg_by(agg_max(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(time_col = max(time_col), int_col = max(int_col)) + new_th4 <- data$th4 |> + agg_by(c(agg_max("time_col"), agg_max("int_col")), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = max(Number1), Number2 = max(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_max(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = max(Number1), Number2 = max(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_max(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_sum behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = sum(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_sum("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = sum(col3)) + new_th2 <- data$th2 |> + agg_by(agg_sum("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = sum(X5), X6 = sum(X6), X7 = sum(X7), X8 = sum(X8)) + new_th3 <- data$th3 |> + agg_by(agg_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(int_col = sum(int_col)) + new_th4 <- data$th4 |> + agg_by(agg_sum("int_col"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = sum(Number1), Number2 = sum(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_sum(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = sum(Number1), Number2 = sum(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_sum(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_abs_sum behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = sum(abs(int_col))) + new_th1 <- data$th1 |> + agg_by(agg_abs_sum("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = sum(abs(col3))) + new_th2 <- data$th2 |> + agg_by(agg_abs_sum("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = sum(abs(X5)), X6 = sum(abs(X6)), X7 = sum(abs(X7)), X8 = sum(abs(X8))) + new_th3 <- data$th3 |> + agg_by(agg_abs_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(int_col = sum(abs(int_col))) + new_th4 <- data$th4 |> + agg_by(agg_abs_sum("int_col"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) + new_th5 <- data$th5 |> + agg_by(agg_abs_sum(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) + new_th6 <- data$th6 |> + agg_by(agg_abs_sum(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_avg behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = mean(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_avg("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = mean(col3)) + new_th2 <- data$th2 |> + agg_by(agg_avg("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = mean(X5), X6 = mean(X6), X7 = mean(X7), X8 = mean(X8)) + new_th3 <- data$th3 |> + agg_by(agg_avg(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(int_col = mean(int_col)) + new_th4 <- data$th4 |> + agg_by(agg_avg("int_col"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = mean(Number1), Number2 = mean(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_avg(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = mean(Number1), Number2 = mean(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_avg(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_w_avg behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = weighted.mean(int_col, dbl_col)) + new_th1 <- data$th1 |> + agg_by(agg_w_avg("dbl_col", "int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = weighted.mean(col3, col1)) + new_th2 <- data$th2 |> + agg_by(agg_w_avg("col1", "col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise( + X5 = weighted.mean(X5, X9), X6 = weighted.mean(X6, X9), + X7 = weighted.mean(X7, X9), X8 = weighted.mean(X8, X9) + ) + new_th3 <- data$th3 |> + agg_by(agg_w_avg("X9", c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(int_col = weighted.mean(int_col, int_col)) + new_th4 <- data$th4 |> + agg_by(agg_w_avg("int_col", "int_col"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + mutate(weights = Number1 * Number2) |> + summarise( + Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights) + ) + new_th5 <- data$th5 |> + update("weights = Number1 * Number2") |> + agg_by(agg_w_avg("weights", c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + mutate(weights = Number1 * Number2) |> + summarise(Number1 = weighted.mean(Number1, weights), Number2 = weighted.mean(Number2, weights)) + new_th6 <- data$th6 |> + update("weights = Number1 * Number2") |> + agg_by(agg_w_avg("weights", c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_median behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = median(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_median("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = median(col3)) + new_th2 <- data$th2 |> + agg_by(agg_median("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = median(X5), X6 = median(X6), X7 = median(X7), X8 = median(X8)) + new_th3 <- data$th3 |> + agg_by(agg_median(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(int_col = median(int_col)) + new_th4 <- data$th4 |> + agg_by(agg_median("int_col"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = median(Number1), Number2 = median(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_median(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = median(Number1), Number2 = median(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_median(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_var behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = var(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_var("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = var(col3)) + new_th2 <- data$th2 |> + agg_by(agg_var("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = var(X5), X6 = var(X6), X7 = var(X7), X8 = var(X8)) + new_th3 <- data$th3 |> + agg_by(agg_var(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(int_col = var(int_col)) + new_th4 <- data$th4 |> + agg_by(agg_var("int_col"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = var(Number1), Number2 = var(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_var(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = var(Number1), Number2 = var(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_var(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_std behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = sd(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_std("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = sd(col3)) + new_th2 <- data$th2 |> + agg_by(agg_std("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = sd(X5), X6 = sd(X6), X7 = sd(X7), X8 = sd(X8)) + new_th3 <- data$th3 |> + agg_by(agg_std(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(int_col = sd(int_col)) + new_th4 <- data$th4 |> + agg_by(agg_std("int_col"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = sd(Number1), Number2 = sd(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_std(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = sd(Number1), Number2 = sd(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_std(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + +test_that("agg_percentile behaves as expected", { + # There is not a clean analog to agg_percentile in dplyr, so we create the + # dataframes directly, and only make comparisons on deterministic data frames. + + data <- setup() + + new_df1 <- data.frame(int_col = 2) + new_th1 <- data$th1 |> + agg_by(agg_percentile(0.4, "int_col")) + expect_equal(as.data.frame(new_th1), new_df1) + + new_df2 <- data.frame( + X = c("A", "B", "C"), + Number1 = c(50, 18, 11), + Number2 = c(-50, 137, 214) + ) + new_th2 <- data$th5 |> + agg_by(agg_percentile(0.6, c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th2), new_df2) + + new_df3 <- data.frame( + X = c("A", "A", "B", "B", "B", "C", "C"), + Y = c("O", "P", "M", "N", "O", "N", "P"), + Number1 = c(-5, -45, 86, 55, 99, -65, 0), + Number2 = c(6, 34, -6, 76, 34, -5, -76) + ) + new_th3 <- data$th6 |> + agg_by(agg_percentile(0.3, c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th3), new_df3) + + close(data$client) +}) + +test_that("agg_count behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + count(string_col) + new_th1 <- data$th1 |> + agg_by(agg_count("n"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + count(col1, col2) + new_th2 <- data$th2 |> + agg_by(agg_count("n"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + count(X1, X2, X3, X4) + new_th3 <- data$th3 |> + agg_by(agg_count("n"), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + count(bool_col) + new_th4 <- data$th4 |> + agg_by(agg_count("n"), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + count(X) + new_th5 <- data$th5 |> + agg_by(agg_count("n"), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + count(X, Y) + new_th6 <- data$th6 |> + agg_by(agg_count("n"), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by_magrittr_pipe.R similarity index 100% rename from R/rdeephaven/inst/tests/testthat/test_agg_by.R rename to R/rdeephaven/inst/tests/testthat/test_agg_by_magrittr_pipe.R diff --git a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R index 9f305f71933..0c8341330eb 100644 --- a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R @@ -3,139 +3,139 @@ library(rdeephaven) ##### TESTING BAD INPUTS ##### -test_that("agg_min fails nicely when 'columns' is a bad type", { +test_that("agg_min fails nicely when 'cols' is a bad type", { expect_error( agg_min(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_min(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_max fails nicely when 'columns' is a bad type", { +test_that("agg_max fails nicely when 'cols' is a bad type", { expect_error( agg_max(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_max(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_sum fails nicely when 'columns' is a bad type", { +test_that("agg_sum fails nicely when 'cols' is a bad type", { expect_error( agg_sum(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_sum(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_abs_sum fails nicely when 'columns' is a bad type", { +test_that("agg_abs_sum fails nicely when 'cols' is a bad type", { expect_error( agg_abs_sum(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_abs_sum(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_avg fails nicely when 'columns' is a bad type", { +test_that("agg_avg fails nicely when 'cols' is a bad type", { expect_error( agg_avg(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_avg(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_w_avg fails nicely when 'weight_column' is a bad type", { +test_that("agg_w_avg fails nicely when 'wcol' is a bad type", { expect_error( agg_w_avg(5, "string"), - "'weight_column' must be passed as a single string. Got an object of class numeric instead." + "'wcol' must be passed as a single string. Got an object of class numeric instead." ) expect_error( agg_w_avg(TRUE, "string"), - "'weight_column' must be passed as a single string. Got an object of class logical instead." + "'wcol' must be passed as a single string. Got an object of class logical instead." ) expect_error( agg_w_avg(c("Multiple", "strings", "bad"), "string"), - "'weight_column' must be passed as a single string. Got a string vector of length 3 instead." + "'wcol' must be passed as a single string. Got a string vector of length 3 instead." ) }) -test_that("agg_w_avg fails nicely when 'columns' is a bad type", { +test_that("agg_w_avg fails nicely when 'cols' is a bad type", { expect_error( agg_w_avg("string", 5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_w_avg("string", TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_var fails nicely when 'columns' is a bad type", { +test_that("agg_var fails nicely when 'cols' is a bad type", { expect_error( agg_var(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_var(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_std fails nicely when 'columns' is a bad type", { +test_that("agg_std fails nicely when 'cols' is a bad type", { expect_error( agg_std(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_std(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_first fails nicely when 'columns' is a bad type", { +test_that("agg_first fails nicely when 'cols' is a bad type", { expect_error( agg_first(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_first(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_last fails nicely when 'columns' is a bad type", { +test_that("agg_last fails nicely when 'cols' is a bad type", { expect_error( agg_last(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_last(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_median fails nicely when 'columns' is a bad type", { +test_that("agg_median fails nicely when 'cols' is a bad type", { expect_error( agg_median(5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_median(TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) @@ -158,28 +158,28 @@ test_that("agg_percentile fails nicely when 'percentile' is bad", { ) }) -test_that("agg_percentile fails nicely when 'columns' is a bad type", { +test_that("agg_percentile fails nicely when 'cols' is a bad type", { expect_error( agg_percentile(0.5, 5), - "'columns' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." ) expect_error( agg_percentile(0.5, TRUE), - "'columns' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." ) }) -test_that("agg_count fails nicely when 'count_column' is a bad type", { +test_that("agg_count fails nicely when 'col' is a bad type", { expect_error( agg_count(5), - "'count_column' must be passed as a single string. Got an object of class numeric instead." + "'col' must be passed as a single string. Got an object of class numeric instead." ) expect_error( agg_count(TRUE), - "'count_column' must be passed as a single string. Got an object of class logical instead." + "'col' must be passed as a single string. Got an object of class logical instead." ) expect_error( agg_count(c("Many", "strings")), - "'count_column' must be passed as a single string. Got a string vector of length 2 instead." + "'col' must be passed as a single string. Got a string vector of length 2 instead." ) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 8ac364ef378..bde6978cda2 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -92,7 +92,7 @@ test_that("import_table does not fail with record batch reader inputs of simple # as we have to create data, push it to the server, and name it in order to test open_table(). # Additionally, we assume the correctness of table_handle$to_data_frame() to make concrete comparisons. -test_that("open_table opens the correct table from the server", { +test_that("open_table opens the correct table from the server using %>%", { data <- setup() client <- connect(target = "localhost:10000") @@ -116,7 +116,31 @@ test_that("open_table opens the correct table from the server", { close(client) }) -test_that("empty_table correctly creates tables on the server", { +test_that("open_table opens the correct table from the server using |>", { + data <- setup() + + client <- connect(target = "localhost:10000") + + th1 <- import_table(client, data$df1) + th1 |> bind_to_variable("table1") + expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) + + th2 <- import_table(client, data$df2) + th2 |> bind_to_variable("table2") + expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) + + th3 <- import_table(client, data$df3) + th3 |> bind_to_variable("table3") + expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) + + th4 <- import_table(client, data$df4) + th4 |> bind_to_variable("table4") + expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) + + close(client) +}) + +test_that("empty_table correctly creates tables on the server using %>%", { client <- connect(target = "localhost:10000") th1 <- empty_table(client, 10) %>% update("X = i") @@ -126,6 +150,16 @@ test_that("empty_table correctly creates tables on the server", { close(client) }) +test_that("empty_table correctly creates tables on the server using |>", { + client <- connect(target = "localhost:10000") + + th1 <- empty_table(client, 10) |> update("X = i") + df1 <- data.frame(X = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) + expect_equal(as.data.frame(th1), df1) + + close(client) +}) + # TODO: Test time_table good inputs test_that("run_script correctly runs a python script", { @@ -247,12 +281,12 @@ test_that("empty_table fails nicely with bad inputs", { test_that("time_table fails nicely with bad inputs", { client <- connect(target = "localhost:10000") - expect_error(time_table(client, 1.23, 1000), "'period_nanos' must be an integer. Got 'period_nanos' = 1.23 instead.") - expect_error(time_table(client, 1000, 1.23), "'start_time_nanos' must be an integer. Got 'start_time_nanos' = 1.23 instead.") - expect_error(time_table(client, c(1, 2, 3), 1000), "'period_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") - expect_error(time_table(client, 1000, c(1, 2, 3)), "'start_time_nanos' must be passed as a single numeric. Got a numeric vector of length 3 instead.") - expect_error(time_table(client, "hello!", 1000), "'period_nanos' must be passed as a single numeric. Got an object of class character instead.") - expect_error(time_table(client, 1000, "hello!"), "'start_time_nanos' must be passed as a single numeric. Got an object of class character instead.") + expect_error(time_table(client, 1.23, 1000), "'period' must be an integer. Got 'period' = 1.23 instead.") + expect_error(time_table(client, 1000, 1.23), "'start_time' must be an integer. Got 'start_time' = 1.23 instead.") + expect_error(time_table(client, c(1, 2, 3), 1000), "'period' must be passed as a single numeric. Got a numeric vector of length 3 instead.") + expect_error(time_table(client, 1000, c(1, 2, 3)), "'start_time' must be passed as a single numeric. Got a numeric vector of length 3 instead.") + expect_error(time_table(client, "hello!", 1000), "'period' must be passed as a single numeric. Got an object of class character instead.") + expect_error(time_table(client, 1000, "hello!"), "'start_time' must be passed as a single numeric. Got an object of class character instead.") close(client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R b/R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R new file mode 100644 index 00000000000..f6f32a14431 --- /dev/null +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R @@ -0,0 +1,840 @@ +library(testthat) +library(dplyr) +library(rdeephaven) + +setup <- function() { + df1 <- data.frame( + string_col = c("I", "am", "a", "string", "column"), + int_col = c(0, 1, 2, 3, 4), + dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) + ) + + df2 <- data.frame( + col1 = rep(3.14, 100), + col2 = rep("hello!", 100), + col3 = rnorm(100) + ) + + df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) + + df4 <- data.frame( + time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], + bool_col = sample(c(TRUE, FALSE), 250000, TRUE), + int_col = sample(0:10000, 250000, TRUE) + ) + + df5 <- data.frame( + X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), + Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), + Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214) + ) + + df6 <- data.frame( + X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), + Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), + Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), + Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) + ) + + # set up client + client <- connect(target = "localhost:10000") + + # move dataframes to server and get TableHandles for testing + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) + th5 <- import_table(client, df5) + th6 <- import_table(client, df6) + + return(list( + "client" = client, + "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, + "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6 + )) +} + +##### TESTING GOOD INPUTS ##### + +test_that("merge behaves as expected", { + data <- setup() + + new_df1 <- rbind(data$df5) + new_th1 <- merge(data$th5) + expect_equal(as.data.frame(new_th1), new_df1) + + new_df2 <- rbind(data$df5, data$df6) + new_th2 <- merge(data$th5, data$th6) + expect_equal(as.data.frame(new_th2), new_df2) + + new_df3 <- rbind(data$df5, data$df6, data$df6, data$df5) + new_th3 <- merge(data$th5, data$th6, data$th6, data$th5) + expect_equal(as.data.frame(new_th3), new_df3) + + new_th4 <- merge(data$th5, NULL) + expect_equal(as.data.frame(new_th4), new_df1) + + new_th5 <- merge(NULL, data$th5) + expect_equal(as.data.frame(new_th5), new_df1) + + new_th6 <- merge(c(data$th5, data$th6)) + expect_equal(as.data.frame(new_th6), new_df2) + + new_th7 <- merge(NULL, c(data$th5, data$th6)) + expect_equal(as.data.frame(new_th7), new_df2) + + new_th8 <- merge(c(data$th5, data$th6), NULL) + expect_equal(as.data.frame(new_th8), new_df2) + + new_th9 <- merge(data$th5, c(data$th6, data$th6, data$th5)) + expect_equal(as.data.frame(new_th9), new_df3) + + new_th10 <- merge(c(data$th5, data$th6, data$th6), data$th5) + expect_equal(as.data.frame(new_th10), new_df3) + + new_th11 <- merge(c(data$th5, data$th6), c(data$th6, data$th5)) + expect_equal(as.data.frame(new_th11), new_df3) + + new_th12 <- merge(c(data$th5, data$th6, data$th6, data$th5)) + expect_equal(as.data.frame(new_th12), new_df3) + +}) + +test_that("select behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::select(string_col) + new_th1 <- data$th1 |> + select("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::select(col2, col3) + new_th2 <- data$th2 |> + select(c("col2", "col3")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::select(X1, X2) |> + rename(first_col = X1) + new_th3 <- data$th3 |> + select(c("first_col = X1", "X2")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::select(int_col) |> + mutate(new_col = int_col + 1, .keep = "none") + new_th4 <- data$th4 |> + select("new_col = int_col + 1") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + mutate(Number3 = Number1 * Number2) |> + dplyr::select(X, Number3) + new_th5 <- data$th5 |> + select(c("X", "Number3 = Number1 * Number2")) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + close(data$client) +}) + +test_that("view behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::select(string_col) + new_th1 <- data$th1 |> + view("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::select(col2, col3) + new_th2 <- data$th2 |> + view(c("col2", "col3")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::select(X1, X2) |> + rename(first_col = X1) + new_th3 <- data$th3 |> + view(c("first_col = X1", "X2")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::select(int_col) |> + mutate(new_col = int_col + 1, .keep = "none") + new_th4 <- data$th4 |> + view("new_col = int_col + 1") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + mutate(Number3 = Number1 * Number2) |> + dplyr::select(X, Number3) + new_th5 <- data$th5 |> + view(c("X", "Number3 = Number1 * Number2")) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + close(data$client) +}) + +test_that("update behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + mutate(dbl_col_again = dbl_col) + new_th1 <- data$th1 |> + update("dbl_col_again = dbl_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + mutate(col4 = col3 * 2) + new_th2 <- data$th2 |> + update("col4 = col3 * 2") + expect_equal(as.data.frame(new_tb2), as.data.frame(new_th2)) + + new_tb3 <- data$df3 |> + mutate(X1001 = X1000, X1002 = X1001) + new_th3 <- data$th3 |> + update(c("X1001 = X1000", "X1002 = X1001")) + expect_equal(as.data.frame(new_tb3), as.data.frame(new_th3)) + + new_tb4 <- data$df4 |> + mutate(new_col = sqrt(3 * int_col)) + new_th4 <- data$th4 |> + update("new_col = sqrt(3 * int_col)") + expect_equal(as.data.frame(new_tb4), as.data.frame(new_th4)) + + new_tb5 <- data$df5 |> + mutate(Number3 = Number1 + Number2) + new_th5 <- data$th5 |> + update("Number3 = Number1 + Number2") + expect_equal(as.data.frame(new_tb5), as.data.frame(new_th5)) + + close(data$client) +}) + +test_that("update_view behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + mutate(dbl_col_again = dbl_col) + new_th1 <- data$th1 |> + update_view("dbl_col_again = dbl_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + mutate(col4 = col3 * 2) + new_th2 <- data$th2 |> + update_view("col4 = col3 * 2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + mutate(X1001 = X1000, X1002 = X1001) + new_th3 <- data$th3 |> + update_view(c("X1001 = X1000", "X1002 = X1001")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + mutate(new_col = sqrt(3 * int_col)) + new_th4 <- data$th4 |> + update_view("new_col = sqrt(3 * int_col)") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + mutate(Number3 = Number1 + Number2) + new_th5 <- data$th5 |> + update_view("Number3 = Number1 + Number2") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + close(data$client) +}) + +test_that("drop_columns behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::select(-string_col) + new_th1 <- data$th1 |> + drop_columns("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::select(-c(col1, col2)) + new_th2 <- data$th2 |> + drop_columns(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::select(-paste0("X", seq(2, 1000))) + new_th3 <- data$th3 |> + drop_columns(paste0("X", seq(2, 1000))) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + close(data$client) +}) + +test_that("where behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + filter(int_col < 3) + new_th1 <- data$th1 |> + where("int_col < 3") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + filter(col2 == "hello!") + new_th2 <- data$th2 |> + where("col2 == `hello!`") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + filter(X1 - X4 + X8 + X32 - 2 * X5 >= 0) + new_th3 <- data$th3 |> + where("X1 - X4 + X8 + X32 - 2*X5 >= 0") + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + close(data$client) +}) + +test_that("group_by and ungroup behave as expected", { + data <- setup() + + # There is not a clean analog to group_by() in dplyr, so we evaluate + # correctness by evaluating that these functions behave as inverses. + # Easiest when grouping columns are first, otherwise we must also reorder. + + new_th1 <- data$th1 |> + group_by("string_col") |> + ungroup() |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(data$th1 |> sort("string_col"))) + + new_th3 <- data$th3 |> + group_by(c("X1", "X2", "X3", "X4", "X5")) |> + ungroup() |> + sort(c("X1", "X2", "X3", "X4", "X5")) + expect_equal(as.data.frame(new_th3), as.data.frame(data$th3 |> sort(c("X1", "X2", "X3", "X4", "X5")))) + + new_th5 <- data$th5 |> + group_by("X") |> + ungroup() |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(data$th5 |> sort("X"))) + + new_th6 <- data$th6 |> + group_by(c("X", "Y")) |> + ungroup() |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(data$th6 |> sort(c("X", "Y")))) + + close(data$client) +}) + +test_that("first_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), first)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + first_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), first)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + first_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("last_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), last)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + last_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), last)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + last_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("head_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::group_by(X) |> + slice_head(n = 2) + new_th1 <- data$th5 |> + head_by(2, "X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + slice_head(n = 2) + new_th2 <- data$th5 |> + head_by(2, c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("tail_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::group_by(X) |> + slice_tail(n = 2) + new_th1 <- data$th5 |> + tail_by(2, "X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + slice_tail(n = 2) + new_th2 <- data$th5 |> + tail_by(2, c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("min_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(int_col) |> + summarise(across(everything(), min)) + new_th1 <- data$th1 |> + min_by("int_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col2) |> + summarise(across(everything(), min)) + new_th2 <- data$th2 |> + min_by("col2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) |> + dplyr::group_by(bool_col1, bool_col2) |> + summarise(across(everything(), min)) |> + arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same + new_th3 <- data$th3 |> + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) |> + min_by(c("bool_col1", "bool_col2")) |> + sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(across(everything(), min)) |> + arrange(bool_col) + new_th4 <- data$th4 |> + min_by("bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + close(data$client) +}) + +test_that("max_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(int_col) |> + summarise(across(everything(), max)) + new_th1 <- data$th1 |> + max_by("int_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col2) |> + summarise(across(everything(), max)) + new_th2 <- data$th2 |> + max_by("col2") + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) |> + dplyr::group_by(bool_col1, bool_col2) |> + summarise(across(everything(), max)) |> + arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same + new_th3 <- data$th3 |> + update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) |> + max_by(c("bool_col1", "bool_col2")) |> + sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(across(everything(), max)) |> + arrange(bool_col) + new_th4 <- data$th4 |> + max_by("bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + close(data$client) +}) + +test_that("sum_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), sum)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + sum_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), sum)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + sum_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("abs_sum_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + mutate(Number1 = abs(Number1), Number2 = abs(Number2)) |> + dplyr::group_by(X) |> + summarise(across(everything(), sum)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + abs_sum_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + mutate(Number1 = abs(Number1), Number2 = abs(Number2)) |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), sum)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + abs_sum_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("avg_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), mean)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + avg_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), mean)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + avg_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("w_avg_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + mutate(weights = Number1 * Number2) |> + dplyr::group_by(X) |> + summarise( + Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights) + ) + new_th1 <- data$th5 |> + drop_columns("Y") |> + update("weights = Number1 * Number2") |> + w_avg_by("weights", "X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + mutate(weights = Number1 * Number2) |> + dplyr::group_by(X, Y) |> + summarise( + Number1 = weighted.mean(Number1, weights), + Number2 = weighted.mean(Number2, weights) + ) |> + arrange(X, Y) + new_th2 <- data$th5 |> + update("weights = Number1 * Number2") |> + w_avg_by("weights", c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("median_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), median)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + median_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), median)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + median_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("var_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), var)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + var_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), var)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + var_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("std_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), sd)) + new_th1 <- data$th5 |> + drop_columns("Y") |> + std_by("X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + dplyr::group_by(X, Y) |> + summarise(across(everything(), sd)) |> + arrange(X, Y) + new_th2 <- data$th5 |> + std_by(c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("percentile_by behaves as expected", { + data <- setup() + + # There is not a clean analog to `percentile_by` in dplyr, + # so we construct these data frames directly. + + new_df1 <- data.frame( + X = c("A", "B", "C"), + Number1 = c(50, -44, -70), + Number2 = c(-50, 76, 130) + ) + new_th1 <- data$th5 |> + drop_columns("Y") |> + percentile_by(0.4, "X") + expect_equal(as.data.frame(new_th1), new_df1) + + new_df2 <- data.frame( + X = c("A", "B", "A", "C", "B", "B", "C"), + Y = c("M", "N", "O", "N", "P", "O", "M"), + Number1 = c(50, -44, 49, 11, -66, 29, -70), + Number2 = c(-55, 76, 20, 130, 137, 73, 214) + ) + new_th2 <- data$th5 |> + percentile_by(0.4, c("X", "Y")) + expect_equal(as.data.frame(new_th2), new_df2) + + + close(data$client) +}) + +test_that("count_by behaves as expected", { + data <- setup() + + new_tb1 <- data$df5 |> + count(X) + new_th1 <- data$th5 |> + count_by("n", "X") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df5 |> + count(X, Y) + new_th2 <- data$th5 |> + count_by("n", c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + close(data$client) +}) + +test_that("sort behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + arrange(dbl_col) + new_th1 <- data$th1 |> + sort("dbl_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + arrange(desc(col3)) + new_th2 <- data$th2 |> + sort("col3", descending = TRUE) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + arrange(X1, X2, X3, X4, X5) + new_th3 <- data$th3 |> + sort(c("X1", "X2", "X3", "X4", "X5")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + arrange(desc(bool_col), desc(int_col)) + new_th4 <- data$th4 |> + sort(c("bool_col", "int_col"), descending = TRUE) + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + arrange(X, desc(Y), Number1) + new_th5 <- data$th5 |> + sort(c("X", "Y", "Number1"), descending = c(FALSE, TRUE, FALSE)) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + close(data$client) +}) + +test_that("cross_join behaves as expected", { + data <- setup() + + new_th1 <- data$th5 |> + cross_join(data$th6, + columns_to_match = character(), + columns_to_add = c("X_y = X", "Y_y = Y", "Number1_y = Number1", "Number2_y = Number2") + ) + new_tb1 <- data$df5 |> + dplyr::cross_join(data$df6) |> + rename( + X = X.x, Y = Y.x, Number1 = Number1.x, Number2 = Number2.x, + X_y = X.y, Y_y = Y.y, Number1_y = Number1.y, Number2_y = Number2.y + ) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + close(data$client) +}) + +test_that("natural_join behaves as expected", { + data <- setup() + + new_th2 <- data$th6 |> + drop_columns("Y") |> + avg_by("X") + new_th1 <- data$th5 |> + natural_join(new_th2, + columns_to_match = "X", + columns_to_add = c("Number3 = Number1", "Number4 = Number2") + ) + + new_tb2 <- data$df6 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), mean)) + new_tb1 <- data$df5 |> + left_join(new_tb2, by = "X") |> + rename( + Number1 = Number1.x, Number2 = Number2.x, + Number3 = Number1.y, Number4 = Number2.y + ) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + close(data$client) +}) + +# TODO: Verify that inner_join is the analog of exact_join +test_that("exact_join behaves as expected", { + data <- setup() + + new_th2 <- data$th6 |> + drop_columns("Y") |> + avg_by("X") + new_th1 <- data$th5 |> + exact_join(new_th2, + columns_to_match = "X", + columns_to_add = c("Number3 = Number1", "Number4 = Number2") + ) + + new_tb2 <- data$df6 |> + dplyr::select(-Y) |> + dplyr::group_by(X) |> + summarise(across(everything(), mean)) + new_tb1 <- data$df5 |> + inner_join(new_tb2, by = "X") |> + rename(Number1 = Number1.x, Number2 = Number2.x, Number3 = Number1.y, Number4 = Number2.y) + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + close(data$client) +}) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops_magrittr_pipe.R similarity index 100% rename from R/rdeephaven/inst/tests/testthat/test_table_ops.R rename to R/rdeephaven/inst/tests/testthat/test_table_ops_magrittr_pipe.R From 6e06ea9d3cd64225541f0bb7bb0f2bcdf4310f9b Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 8 Aug 2023 16:48:16 -0500 Subject: [PATCH 49/73] Code review suggestions --- R/rdeephaven/NAMESPACE | 1 - R/rdeephaven/R/client_wrapper.R | 66 +- R/rdeephaven/R/helper_functions.R | 42 +- R/rdeephaven/R/table_ops.R | 2 +- R/rdeephaven/README.md | 4 +- ...t_agg_by_magrittr_pipe.R => test_agg_by.R} | 54 ++ .../tests/testthat/test_agg_by_base_pipe.R | 743 ---------------- .../tests/testthat/test_aggregate_wrapper.R | 68 +- .../inst/tests/testthat/test_client_wrapper.R | 54 +- .../testthat/test_table_handle_wrapper.R | 9 +- ...e_ops_magrittr_pipe.R => test_table_ops.R} | 39 + .../tests/testthat/test_table_ops_base_pipe.R | 840 ------------------ 12 files changed, 219 insertions(+), 1703 deletions(-) rename R/rdeephaven/inst/tests/testthat/{test_agg_by_magrittr_pipe.R => test_agg_by.R} (92%) delete mode 100644 R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R rename R/rdeephaven/inst/tests/testthat/{test_table_ops_magrittr_pipe.R => test_table_ops.R} (95%) delete mode 100644 R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 22e18a09f9b..d0312a4daf7 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -13,7 +13,6 @@ export(agg_std) export(agg_sum) export(agg_var) export(agg_w_avg) -export(merge) export(sort) exportClasses(Aggregation) exportClasses(Client) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 0a29ed24211..36f35745453 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -28,50 +28,54 @@ setMethod( string_option = "", extra_header = "") { options <- new(INTERNAL_ClientOptions) + + verify_string("target", target, TRUE) + verify_bool("use_tls", use_tls, TRUE) # check if auth_type needs to be changed and set credentials accordingly - if (auth_type != "anonymous") { - if (auth_type == "basic") { - if (auth_token_pair != "") { - verify_string("auth_token_pair", auth_token_pair, TRUE) - username_password <- strsplit(auth_token_pair, ":", fixed = TRUE) - options$set_basic_authentication(username_password[1], username_password[2]) - } else { - stop("Basic authentication was requested, but no 'auth_token_pair' was provided.") - } - } else if (auth_type == "custom") { - if (auth_token_pair != "") { - verify_string("auth_token_pair", auth_token_pair, TRUE) - key_value <- strsplit(auth_token_pair, ":", fixed = TRUE) - options$set_custom_authentication(key_value[1], key_value[2]) - } else { - stop("Custom authentication was requested, but no 'auth_token_pair' was provided.") - } + if (auth_type == "anonymous") { + options$set_default_authentication() + } + else if (auth_type == "basic") { + if (auth_token_pair != "") { + verify_string("auth_token_pair", auth_token_pair, TRUE) + username_password <- strsplit(auth_token_pair, ":", fixed = TRUE) + options$set_basic_authentication(username_password[1], username_password[2]) + } else { + stop("Basic authentication was requested, but no 'auth_token_pair' was provided.") + } + } + else if (auth_type == "custom") { + if (auth_token_pair != "") { + verify_string("auth_token_pair", auth_token_pair, TRUE) + key_value <- strsplit(auth_token_pair, ":", fixed = TRUE) + options$set_custom_authentication(key_value[1], key_value[2]) } else { - stop(paste0("'auth_type' must be 'anonymous', 'basic', or 'custom', but got ", auth_type, " instead.")) + stop("Custom authentication was requested, but no 'auth_token_pair' was provided.") } } + else { + stop(paste0("'auth_type' must be 'anonymous', 'basic', or 'custom', but got ", auth_type, ".")) + } # set session type if a valid session type is provided if ((session_type == "python") || (session_type == "groovy")) { options$set_session_type(session_type) - } else { - stop(paste0("'session_type' must be 'python' or 'groovy', but got ", session_type, " instead.")) + } + else { + stop(paste0("'session_type' must be 'python' or 'groovy', but got ", session_type, ".")) } # if tls is requested, set it and set the root_certs if provided - if (use_tls != FALSE) { - if (use_tls == TRUE) { - options$set_use_tls() - if (tls_root_certs != "") { - verify_string("tls_root_certs", tls_root_certs, TRUE) - options$set_tls_root_certs(tls_root_certs) - } - } else { - stop(paste0("'use_tls' must be TRUE or FALSE, but got ", use_tls, " instead.")) + if (use_tls == TRUE) { + options$set_use_tls() + if (tls_root_certs != "") { + verify_string("tls_root_certs", tls_root_certs, TRUE) + options$set_tls_root_certs(tls_root_certs) } } + # set extra header options if they are provided if (int_option != "") { verify_string("int_option", int_option, TRUE) new_int_option <- strsplit(int_option, ":", fixed = TRUE) @@ -143,7 +147,7 @@ setMethod( function(client_instance, name) { verify_string("name", name, TRUE) if (!check_for_table(client_instance, name)) { - stop(paste0("The table '", name, "' you're trying to pull does not exist on the server.")) + stop(paste0("The table '", name, "' does not exist on the server.")) } return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$open_table(name))) } @@ -212,7 +216,7 @@ setMethod( table_object_class[[3]] == "ArrowObject")) { rcpp_dh_table <- arrow_to_dh_table(client_instance, table_object) } else { - stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], " instead.")) + stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], ".")) } return(new("TableHandle", .internal_rcpp_object = rcpp_dh_table)) } diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 4fc75f8e4e2..736e7e5b884 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -3,35 +3,37 @@ first_class <- function(arg) { } verify_type <- function(arg_name, candidate, required_type, message_type_name, is_scalar) { + + if (is_scalar) { + if (length(candidate) != 1) { + stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got a vector of length ", length(candidate), ".")) + } + } + if (first_class(candidate) == "list") { if (any(lapply(candidate, first_class) != required_type)) { - stop(paste0("'", arg_name, "' must be a ", message_type_name, ", or a vector of ", message_type_name, "s. Got a vector with at least one element that is not a ", message_type_name, " instead.")) + stop(paste0("'", arg_name, "' must be a ", message_type_name, ", or a vector of ", message_type_name, "s. Got a vector with at least one element that is not a ", message_type_name, ".")) } - } else { + } + else { if (first_class(candidate) != required_type) { if (is_scalar) { - stop(paste0("'", arg_name, "' must be passed as a single ", message_type_name, ". Got an object of class ", first_class(candidate), " instead.")) + stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got an object of class ", first_class(candidate), ".")) } else { - stop(paste0("'", arg_name, "' must be passed as a ", message_type_name, " or a vector of ", message_type_name, "s. Got an object of class ", first_class(candidate), " instead.")) + stop(paste0("'", arg_name, "' must be a ", message_type_name, " or a vector of ", message_type_name, "s. Got an object of class ", first_class(candidate), ".")) } } } - - if (is_scalar) { - if (length(candidate) != 1) { - stop(paste0("'", arg_name, "' must be passed as a single ", message_type_name, ". Got a ", message_type_name, " vector of length ", length(candidate), " instead.")) - } - } } # does not attempt to verify that candidate is numeric -verify_in_range <- function(arg_name, candidate, message, a = NULL, b = NULL, a_open = TRUE, b_open = TRUE) { - if (((!is.null(a)) && ((any(candidate <= a) && (a_open)) || (any(candidate < a) && (!a_open)))) || - ((!is.null(b)) && ((any(candidate >= b) && (b_open)) || (any(candidate > b) && (!b_open))))) { +verify_in_range <- function(arg_name, candidate, message, lb, ub, lb_open, ub_open) { + if (((!is.null(lb)) && ((any(candidate <= lb) && (lb_open)) || (any(candidate < lb) && (!lb_open)))) || + ((!is.null(ub)) && ((any(candidate >= ub) && (ub_open)) || (any(candidate > ub) && (!ub_open))))) { if (length(candidate) == 1) { - stop(paste0("'", arg_name, "' must be ", message, ". Got '", arg_name, "' = ", candidate, " instead.")) + stop(paste0("'", arg_name, "' must be ", message, ". Got '", arg_name, "' = ", candidate, ".")) } else { - stop(paste0("Every element of '", arg_name, "' must be ", message, ". Got at least one element that is not ", message, " instead.")) + stop(paste0("Every element of '", arg_name, "' must be ", message, ". Got at least one element that is not ", message, ".")) } } } @@ -40,9 +42,9 @@ verify_in_range <- function(arg_name, candidate, message, a = NULL, b = NULL, a_ verify_int <- function(arg_name, candidate) { if (candidate != as.integer(candidate)) { if (length(candidate == 1)) { - stop(paste0("'", arg_name, "' must be an integer. Got '", arg_name, "' = ", candidate, " instead.")) + stop(paste0("'", arg_name, "' must be an integer. Got '", arg_name, "' = ", candidate, ".")) } else { - stop(paste0("Every element of '", arg_name, "' must be an integer. Got at least one non-integer element instead.")) + stop(paste0("Every element of '", arg_name, "' must be an integer. Got at least one non-integer element.")) } } } @@ -61,7 +63,7 @@ verify_numeric <- function(arg_name, candidate, is_scalar) { verify_in_unit_interval <- function(arg_name, candidate, is_scalar) { verify_numeric(arg_name, candidate, is_scalar) - verify_in_range(arg_name, candidate, message = "between 0 and 1 inclusive", a = 0, b = 1, a_open = FALSE, b_open = FALSE) + verify_in_range(arg_name, candidate, message = "between 0 and 1 inclusive", lb = 0, ub = 1, lb_open = FALSE, ub_open = FALSE) } verify_any_int <- function(arg_name, candidate, is_scalar) { @@ -72,13 +74,13 @@ verify_any_int <- function(arg_name, candidate, is_scalar) { verify_nonnegative_int <- function(arg_name, candidate, is_scalar) { verify_numeric(arg_name, candidate, is_scalar) verify_int(arg_name, candidate) - verify_in_range(arg_name, candidate, message = "a nonnegative integer", a = 0, a_open = FALSE) + verify_in_range(arg_name, candidate, message = "a nonnegative integer", lb = 0, ub = NULL, lb_open = FALSE, ub_open = TRUE) } verify_positive_int <- function(arg_name, candidate, is_scalar) { verify_numeric(arg_name, candidate, is_scalar) verify_int(arg_name, candidate) - verify_in_range(arg_name, candidate, message = "a positive integer", a = 0) + verify_in_range(arg_name, candidate, message = "a positive integer", lb = 0, ub = NULL, lb_open = TRUE, ub_open = TRUE) } strip_s4_wrapping <- function(s4_object) { diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 07e6e734087..81aef84de91 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -635,7 +635,7 @@ setMethod( verify_string("by", by, FALSE) verify_bool("descending", descending, FALSE) if ((length(descending) > 1) && length(descending) != length(by)) { - stop(paste0("'descending' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'descending' with length", length(descending), " instead.")) + stop(paste0("'descending' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'descending' with length", length(descending), ".")) } return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(by, descending))) } diff --git a/R/rdeephaven/README.md b/R/rdeephaven/README.md index 5b1a698d134..568bdcb54fe 100644 --- a/R/rdeephaven/README.md +++ b/R/rdeephaven/README.md @@ -71,8 +71,10 @@ Currently, the R client is only supported on Ubuntu 20.04 or 22.04 and must be b git pull origin main ``` -3. Start an R console with this command: +3. Start an R console, using some environment variable definitions to speed up compilation. Use these commands: ```bash + export NCPUS=`getconf _NPROCESSORS_ONLN` + export MAKEFLAGS="-j$NCPUS" R ``` In that console, install the dephaven client dependencies (since we are building from source diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by_magrittr_pipe.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R similarity index 92% rename from R/rdeephaven/inst/tests/testthat/test_agg_by_magrittr_pipe.R rename to R/rdeephaven/inst/tests/testthat/test_agg_by.R index 79a4cb452cf..fc9e3b11bde 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by_magrittr_pipe.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -109,6 +109,60 @@ test_that("agg_first behaves as expected", { close(data$client) }) +test_that("agg_first with built-in pipe behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::group_by(string_col) |> + summarise(int_col = first(int_col)) + new_th1 <- data$th1 |> + agg_by(agg_first("int_col"), "string_col") |> + sort("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::group_by(col1, col2) |> + summarise(col3 = first(col3)) + new_th2 <- data$th2 |> + agg_by(agg_first("col3"), c("col1", "col2")) |> + sort(c("col1", "col2")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::group_by(X1, X2, X3, X4) |> + summarise(X5 = first(X5), X6 = first(X6), X7 = first(X7), X8 = first(X8)) + new_th3 <- data$th3 |> + agg_by(agg_first(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> + sort(c("X1", "X2", "X3", "X4")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::group_by(bool_col) |> + summarise(time_col = first(time_col), int_col = first(int_col)) + new_th4 <- data$th4 |> + agg_by(c(agg_first("time_col"), agg_first("int_col")), "bool_col") |> + sort("bool_col") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + dplyr::group_by(X) |> + summarise(Number1 = first(Number1), Number2 = first(Number2)) + new_th5 <- data$th5 |> + agg_by(agg_first(c("Number1", "Number2")), "X") |> + sort("X") + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + new_tb6 <- data$df6 |> + dplyr::group_by(X, Y) |> + summarise(Number1 = first(Number1), Number2 = first(Number2)) + new_th6 <- data$th6 |> + agg_by(agg_first(c("Number1", "Number2")), c("X", "Y")) |> + sort(c("X", "Y")) + expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) + + close(data$client) +}) + test_that("agg_last behaves as expected", { data <- setup() diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R b/R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R deleted file mode 100644 index 580ea51a6c2..00000000000 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by_base_pipe.R +++ /dev/null @@ -1,743 +0,0 @@ -library(testthat) -library(dplyr) -library(rdeephaven) - -setup <- function() { - df1 <- data.frame( - string_col = c("I", "am", "a", "string", "column"), - int_col = c(0, 1, 2, 3, 4), - dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) - ) - - df2 <- data.frame( - col1 = rep(3.14, 100), - col2 = rep("hello!", 100), - col3 = rnorm(100) - ) - - df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) - - df4 <- data.frame( - time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], - bool_col = sample(c(TRUE, FALSE), 250000, TRUE), - int_col = sample(0:10000, 250000, TRUE) - ) - - df5 <- data.frame( - X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), - Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), - Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), - Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214) - ) - - df6 <- data.frame( - X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), - Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), - Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), - Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) - ) - - # set up client - client <- connect(target = "localhost:10000") - - # move dataframes to server and get TableHandles for testing - th1 <- import_table(client, df1) - th2 <- import_table(client, df2) - th3 <- import_table(client, df3) - th4 <- import_table(client, df4) - th5 <- import_table(client, df5) - th6 <- import_table(client, df6) - - return(list( - "client" = client, - "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6 - )) -} - -test_that("agg_first behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = first(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_first("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = first(col3)) - new_th2 <- data$th2 |> - agg_by(agg_first("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = first(X5), X6 = first(X6), X7 = first(X7), X8 = first(X8)) - new_th3 <- data$th3 |> - agg_by(agg_first(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(time_col = first(time_col), int_col = first(int_col)) - new_th4 <- data$th4 |> - agg_by(c(agg_first("time_col"), agg_first("int_col")), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = first(Number1), Number2 = first(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_first(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = first(Number1), Number2 = first(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_first(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_last behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = last(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_last("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = last(col3)) - new_th2 <- data$th2 |> - agg_by(agg_last("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = last(X5), X6 = last(X6), X7 = last(X7), X8 = last(X8)) - new_th3 <- data$th3 |> - agg_by(agg_last(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(time_col = last(time_col), int_col = last(int_col)) - new_th4 <- data$th4 |> - agg_by(c(agg_last("time_col"), agg_last("int_col")), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = last(Number1), Number2 = last(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_last(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = last(Number1), Number2 = last(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_last(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_min behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = min(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_min("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = min(col3)) - new_th2 <- data$th2 |> - agg_by(agg_min("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = min(X5), X6 = min(X6), X7 = min(X7), X8 = min(X8)) - new_th3 <- data$th3 |> - agg_by(agg_min(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(time_col = min(time_col), int_col = min(int_col)) - new_th4 <- data$th4 |> - agg_by(c(agg_min("time_col"), agg_min("int_col")), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = min(Number1), Number2 = min(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_min(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = min(Number1), Number2 = min(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_min(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_max behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = max(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_max("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = max(col3)) - new_th2 <- data$th2 |> - agg_by(agg_max("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = max(X5), X6 = max(X6), X7 = max(X7), X8 = max(X8)) - new_th3 <- data$th3 |> - agg_by(agg_max(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(time_col = max(time_col), int_col = max(int_col)) - new_th4 <- data$th4 |> - agg_by(c(agg_max("time_col"), agg_max("int_col")), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = max(Number1), Number2 = max(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_max(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = max(Number1), Number2 = max(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_max(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_sum behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = sum(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_sum("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = sum(col3)) - new_th2 <- data$th2 |> - agg_by(agg_sum("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = sum(X5), X6 = sum(X6), X7 = sum(X7), X8 = sum(X8)) - new_th3 <- data$th3 |> - agg_by(agg_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(int_col = sum(int_col)) - new_th4 <- data$th4 |> - agg_by(agg_sum("int_col"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = sum(Number1), Number2 = sum(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_sum(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = sum(Number1), Number2 = sum(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_sum(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_abs_sum behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = sum(abs(int_col))) - new_th1 <- data$th1 |> - agg_by(agg_abs_sum("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = sum(abs(col3))) - new_th2 <- data$th2 |> - agg_by(agg_abs_sum("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = sum(abs(X5)), X6 = sum(abs(X6)), X7 = sum(abs(X7)), X8 = sum(abs(X8))) - new_th3 <- data$th3 |> - agg_by(agg_abs_sum(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(int_col = sum(abs(int_col))) - new_th4 <- data$th4 |> - agg_by(agg_abs_sum("int_col"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) - new_th5 <- data$th5 |> - agg_by(agg_abs_sum(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = sum(abs(Number1)), Number2 = sum(abs(Number2))) - new_th6 <- data$th6 |> - agg_by(agg_abs_sum(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_avg behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = mean(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_avg("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = mean(col3)) - new_th2 <- data$th2 |> - agg_by(agg_avg("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = mean(X5), X6 = mean(X6), X7 = mean(X7), X8 = mean(X8)) - new_th3 <- data$th3 |> - agg_by(agg_avg(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(int_col = mean(int_col)) - new_th4 <- data$th4 |> - agg_by(agg_avg("int_col"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = mean(Number1), Number2 = mean(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_avg(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = mean(Number1), Number2 = mean(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_avg(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_w_avg behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = weighted.mean(int_col, dbl_col)) - new_th1 <- data$th1 |> - agg_by(agg_w_avg("dbl_col", "int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = weighted.mean(col3, col1)) - new_th2 <- data$th2 |> - agg_by(agg_w_avg("col1", "col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise( - X5 = weighted.mean(X5, X9), X6 = weighted.mean(X6, X9), - X7 = weighted.mean(X7, X9), X8 = weighted.mean(X8, X9) - ) - new_th3 <- data$th3 |> - agg_by(agg_w_avg("X9", c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(int_col = weighted.mean(int_col, int_col)) - new_th4 <- data$th4 |> - agg_by(agg_w_avg("int_col", "int_col"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - mutate(weights = Number1 * Number2) |> - summarise( - Number1 = weighted.mean(Number1, weights), - Number2 = weighted.mean(Number2, weights) - ) - new_th5 <- data$th5 |> - update("weights = Number1 * Number2") |> - agg_by(agg_w_avg("weights", c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - mutate(weights = Number1 * Number2) |> - summarise(Number1 = weighted.mean(Number1, weights), Number2 = weighted.mean(Number2, weights)) - new_th6 <- data$th6 |> - update("weights = Number1 * Number2") |> - agg_by(agg_w_avg("weights", c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_median behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = median(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_median("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = median(col3)) - new_th2 <- data$th2 |> - agg_by(agg_median("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = median(X5), X6 = median(X6), X7 = median(X7), X8 = median(X8)) - new_th3 <- data$th3 |> - agg_by(agg_median(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(int_col = median(int_col)) - new_th4 <- data$th4 |> - agg_by(agg_median("int_col"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = median(Number1), Number2 = median(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_median(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = median(Number1), Number2 = median(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_median(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_var behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = var(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_var("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = var(col3)) - new_th2 <- data$th2 |> - agg_by(agg_var("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = var(X5), X6 = var(X6), X7 = var(X7), X8 = var(X8)) - new_th3 <- data$th3 |> - agg_by(agg_var(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(int_col = var(int_col)) - new_th4 <- data$th4 |> - agg_by(agg_var("int_col"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = var(Number1), Number2 = var(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_var(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = var(Number1), Number2 = var(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_var(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_std behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(string_col) |> - summarise(int_col = sd(int_col)) - new_th1 <- data$th1 |> - agg_by(agg_std("int_col"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col1, col2) |> - summarise(col3 = sd(col3)) - new_th2 <- data$th2 |> - agg_by(agg_std("col3"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::group_by(X1, X2, X3, X4) |> - summarise(X5 = sd(X5), X6 = sd(X6), X7 = sd(X7), X8 = sd(X8)) - new_th3 <- data$th3 |> - agg_by(agg_std(c("X5", "X6", "X7", "X8")), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(int_col = sd(int_col)) - new_th4 <- data$th4 |> - agg_by(agg_std("int_col"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - dplyr::group_by(X) |> - summarise(Number1 = sd(Number1), Number2 = sd(Number2)) - new_th5 <- data$th5 |> - agg_by(agg_std(c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - dplyr::group_by(X, Y) |> - summarise(Number1 = sd(Number1), Number2 = sd(Number2)) - new_th6 <- data$th6 |> - agg_by(agg_std(c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) - -test_that("agg_percentile behaves as expected", { - # There is not a clean analog to agg_percentile in dplyr, so we create the - # dataframes directly, and only make comparisons on deterministic data frames. - - data <- setup() - - new_df1 <- data.frame(int_col = 2) - new_th1 <- data$th1 |> - agg_by(agg_percentile(0.4, "int_col")) - expect_equal(as.data.frame(new_th1), new_df1) - - new_df2 <- data.frame( - X = c("A", "B", "C"), - Number1 = c(50, 18, 11), - Number2 = c(-50, 137, 214) - ) - new_th2 <- data$th5 |> - agg_by(agg_percentile(0.6, c("Number1", "Number2")), "X") |> - sort("X") - expect_equal(as.data.frame(new_th2), new_df2) - - new_df3 <- data.frame( - X = c("A", "A", "B", "B", "B", "C", "C"), - Y = c("O", "P", "M", "N", "O", "N", "P"), - Number1 = c(-5, -45, 86, 55, 99, -65, 0), - Number2 = c(6, 34, -6, 76, 34, -5, -76) - ) - new_th3 <- data$th6 |> - agg_by(agg_percentile(0.3, c("Number1", "Number2")), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th3), new_df3) - - close(data$client) -}) - -test_that("agg_count behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - count(string_col) - new_th1 <- data$th1 |> - agg_by(agg_count("n"), "string_col") |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - count(col1, col2) - new_th2 <- data$th2 |> - agg_by(agg_count("n"), c("col1", "col2")) |> - sort(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - count(X1, X2, X3, X4) - new_th3 <- data$th3 |> - agg_by(agg_count("n"), c("X1", "X2", "X3", "X4")) |> - sort(c("X1", "X2", "X3", "X4")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - count(bool_col) - new_th4 <- data$th4 |> - agg_by(agg_count("n"), "bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - count(X) - new_th5 <- data$th5 |> - agg_by(agg_count("n"), "X") |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - new_tb6 <- data$df6 |> - count(X, Y) - new_th6 <- data$th6 |> - agg_by(agg_count("n"), c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(new_tb6)) - - close(data$client) -}) diff --git a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R index 0c8341330eb..d68e36f414b 100644 --- a/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_aggregate_wrapper.R @@ -6,180 +6,180 @@ library(rdeephaven) test_that("agg_min fails nicely when 'cols' is a bad type", { expect_error( agg_min(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_min(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_max fails nicely when 'cols' is a bad type", { expect_error( agg_max(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_max(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_sum fails nicely when 'cols' is a bad type", { expect_error( agg_sum(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_sum(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_abs_sum fails nicely when 'cols' is a bad type", { expect_error( agg_abs_sum(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_abs_sum(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_avg fails nicely when 'cols' is a bad type", { expect_error( agg_avg(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_avg(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_w_avg fails nicely when 'wcol' is a bad type", { expect_error( agg_w_avg(5, "string"), - "'wcol' must be passed as a single string. Got an object of class numeric instead." + "'wcol' must be a single string. Got an object of class numeric." ) expect_error( agg_w_avg(TRUE, "string"), - "'wcol' must be passed as a single string. Got an object of class logical instead." + "'wcol' must be a single string. Got an object of class logical." ) expect_error( agg_w_avg(c("Multiple", "strings", "bad"), "string"), - "'wcol' must be passed as a single string. Got a string vector of length 3 instead." + "'wcol' must be a single string. Got a vector of length 3." ) }) test_that("agg_w_avg fails nicely when 'cols' is a bad type", { expect_error( agg_w_avg("string", 5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_w_avg("string", TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_var fails nicely when 'cols' is a bad type", { expect_error( agg_var(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_var(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_std fails nicely when 'cols' is a bad type", { expect_error( agg_std(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_std(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_first fails nicely when 'cols' is a bad type", { expect_error( agg_first(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_first(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_last fails nicely when 'cols' is a bad type", { expect_error( agg_last(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_last(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_median fails nicely when 'cols' is a bad type", { expect_error( agg_median(5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_median(TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_percentile fails nicely when 'percentile' is bad", { expect_error( agg_percentile("string", "string"), - "'percentile' must be passed as a single numeric. Got an object of class character instead." + "'percentile' must be a single numeric. Got an object of class character." ) expect_error( agg_percentile(TRUE, "string"), - "'percentile' must be passed as a single numeric. Got an object of class logical instead." + "'percentile' must be a single numeric. Got an object of class logical." ) expect_error( agg_percentile(5, "string"), - "'percentile' must be between 0 and 1 inclusive. Got 'percentile' = 5 instead." + "'percentile' must be between 0 and 1 inclusive. Got 'percentile' = 5." ) expect_error( agg_percentile(c(5, 6, 7, 8), "string"), - "'percentile' must be passed as a single numeric. Got a numeric vector of length 4 instead." + "'percentile' must be a single numeric. Got a vector of length 4." ) }) test_that("agg_percentile fails nicely when 'cols' is a bad type", { expect_error( agg_percentile(0.5, 5), - "'cols' must be passed as a string or a vector of strings. Got an object of class numeric instead." + "'cols' must be a string or a vector of strings. Got an object of class numeric." ) expect_error( agg_percentile(0.5, TRUE), - "'cols' must be passed as a string or a vector of strings. Got an object of class logical instead." + "'cols' must be a string or a vector of strings. Got an object of class logical." ) }) test_that("agg_count fails nicely when 'col' is a bad type", { expect_error( agg_count(5), - "'col' must be passed as a single string. Got an object of class numeric instead." + "'col' must be a single string. Got an object of class numeric." ) expect_error( agg_count(TRUE), - "'col' must be passed as a single string. Got an object of class logical instead." + "'col' must be a single string. Got an object of class logical." ) expect_error( agg_count(c("Many", "strings")), - "'col' must be passed as a single string. Got a string vector of length 2 instead." + "'col' must be a single string. Got a vector of length 2." ) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index bde6978cda2..09070d39546 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -196,35 +196,35 @@ test_that("connect fails nicely with bad inputs", { ) expect_error( connect(target = "localhost:10000", auth_type = "blahblah"), - "'auth_type' must be 'anonymous', 'basic', or 'custom', but got blahblah instead." + "'auth_type' must be 'anonymous', 'basic', or 'custom', but got blahblah." ) expect_error( connect(target = "localhost:10000", auth_type = "basic", auth_token_pair = 1234), - "'auth_token_pair' must be passed as a single string. Got an object of class numeric instead." + "'auth_token_pair' must be a single string. Got an object of class numeric." ) expect_error( connect(target = "localhost:10000", session_type = "blahblah"), - "'session_type' must be 'python' or 'groovy', but got blahblah instead." + "'session_type' must be 'python' or 'groovy', but got blahblah." ) expect_error( connect(target = "localhost:10000", session_type = 1234), - "'session_type' must be 'python' or 'groovy', but got 1234 instead." + "'session_type' must be 'python' or 'groovy', but got 1234." ) expect_error( connect(target = "localhost:10000", use_tls = "banana"), - "'use_tls' must be TRUE or FALSE, but got banana instead." + "'use_tls' must be a single boolean. Got an object of class character." ) expect_error( connect(target = "localhost:10000", int_option = 1234), - "'int_option' must be passed as a single string. Got an object of class numeric instead." + "'int_option' must be a single string. Got an object of class numeric." ) expect_error( connect(target = "localhost:10000", string_option = 1234), - "'string_option' must be passed as a single string. Got an object of class numeric instead." + "'string_option' must be a single string. Got an object of class numeric." ) expect_error( connect(target = "localhost:10000", extra_header = 1234), - "'extra_header' must be passed as a single string. Got an object of class numeric instead." + "'extra_header' must be a single string. Got an object of class numeric." ) }) @@ -236,11 +236,11 @@ test_that("import_table fails nicely with bad inputs", { expect_error( import_table(client, 12345), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class numeric instead." + "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class numeric." ) expect_error( import_table(client, "hello!"), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class character instead." + "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class character." ) # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. @@ -250,7 +250,7 @@ test_that("import_table fails nicely with bad inputs", { data(HairEyeColor) expect_error( import_table(client, HairEyeColor), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class table instead." + "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class table." ) close(client) @@ -259,9 +259,9 @@ test_that("import_table fails nicely with bad inputs", { test_that("open_table fails nicely with bad inputs", { client <- connect(target = "localhost:10000") - expect_error(open_table(client, ""), "The table '' you're trying to pull does not exist on the server.") - expect_error(open_table(client, 12345), "'name' must be passed as a single string. Got an object of class numeric instead.") - expect_error(open_table(client, c("I", "am", "string")), "'name' must be passed as a single string. Got a string vector of length 3 instead.") + expect_error(open_table(client, ""), "The table '' does not exist on the server.") + expect_error(open_table(client, 12345), "'name' must be a single string. Got an object of class numeric.") + expect_error(open_table(client, c("I", "am", "string")), "'name' must be a single string. Got a vector of length 3.") close(client) }) @@ -269,11 +269,11 @@ test_that("open_table fails nicely with bad inputs", { test_that("empty_table fails nicely with bad inputs", { client <- connect(target = "localhost:10000") - expect_error(empty_table(client, 0), "'size' must be a positive integer. Got 'size' = 0 instead.") - expect_error(empty_table(client, -3), "'size' must be a positive integer. Got 'size' = -3 instead.") - expect_error(empty_table(client, 1.2345), "'size' must be an integer. Got 'size' = 1.2345 instead.") - expect_error(empty_table(client, "hello!"), "'size' must be passed as a single numeric. Got an object of class character instead.") - expect_error(empty_table(client, c(1, 2, 3, 4)), "'size' must be passed as a single numeric. Got a numeric vector of length 4 instead.") + expect_error(empty_table(client, 0), "'size' must be a positive integer. Got 'size' = 0.") + expect_error(empty_table(client, -3), "'size' must be a positive integer. Got 'size' = -3.") + expect_error(empty_table(client, 1.2345), "'size' must be an integer. Got 'size' = 1.2345.") + expect_error(empty_table(client, "hello!"), "'size' must be a single numeric. Got an object of class character.") + expect_error(empty_table(client, c(1, 2, 3, 4)), "'size' must be a single numeric. Got a vector of length 4.") close(client) }) @@ -281,12 +281,12 @@ test_that("empty_table fails nicely with bad inputs", { test_that("time_table fails nicely with bad inputs", { client <- connect(target = "localhost:10000") - expect_error(time_table(client, 1.23, 1000), "'period' must be an integer. Got 'period' = 1.23 instead.") - expect_error(time_table(client, 1000, 1.23), "'start_time' must be an integer. Got 'start_time' = 1.23 instead.") - expect_error(time_table(client, c(1, 2, 3), 1000), "'period' must be passed as a single numeric. Got a numeric vector of length 3 instead.") - expect_error(time_table(client, 1000, c(1, 2, 3)), "'start_time' must be passed as a single numeric. Got a numeric vector of length 3 instead.") - expect_error(time_table(client, "hello!", 1000), "'period' must be passed as a single numeric. Got an object of class character instead.") - expect_error(time_table(client, 1000, "hello!"), "'start_time' must be passed as a single numeric. Got an object of class character instead.") + expect_error(time_table(client, 1.23, 1000), "'period' must be an integer. Got 'period' = 1.23.") + expect_error(time_table(client, 1000, 1.23), "'start_time' must be an integer. Got 'start_time' = 1.23.") + expect_error(time_table(client, c(1, 2, 3), 1000), "'period' must be a single numeric. Got a vector of length 3.") + expect_error(time_table(client, 1000, c(1, 2, 3)), "'start_time' must be a single numeric. Got a vector of length 3.") + expect_error(time_table(client, "hello!", 1000), "'period' must be a single numeric. Got an object of class character.") + expect_error(time_table(client, 1000, "hello!"), "'start_time' must be a single numeric. Got an object of class character.") close(client) }) @@ -294,8 +294,8 @@ test_that("time_table fails nicely with bad inputs", { test_that("run_script fails nicely with bad input types", { client <- connect(target = "localhost:10000") - expect_error(run_script(client, 12345), "'script' must be passed as a single string. Got an object of class numeric instead.") - expect_error(run_script(client, c("I", "am", "a", "string")), "'script' must be passed as a single string. Got a string vector of length 4 instead.") + expect_error(run_script(client, 12345), "'script' must be a single string. Got an object of class numeric.") + expect_error(run_script(client, c("I", "am", "a", "string")), "'script' must be a single string. Got a vector of length 4.") close(client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index e762436be24..a03da33bce0 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -55,7 +55,6 @@ test_that("is_static returns the correct value", { close(data$client) }) -# TODO: Implement so this doesn't fail test_that("nrow returns the correct number of rows", { data <- setup() @@ -172,22 +171,22 @@ test_that("bind_to_variable fails nicely on bad inputs", { expect_error( data$th1 %>% bind_to_variable(12345), - "'name' must be passed as a single string. Got an object of class numeric instead." + "'name' must be a single string. Got an object of class numeric." ) expect_error( data$th1 %>% bind_to_variable(c("multiple", "strings")), - "'name' must be passed as a single string. Got a string vector of length 2 instead." + "'name' must be a single string. Got a vector of length 2." ) expect_error( data$th1 %>% bind_to_variable(data$df1), - "'name' must be passed as a single string. Got an object of class data.frame instead." + "'name' must be a single string. Got a vector of length 3." ) expect_error( data$th1 %>% bind_to_variable(list("list", "of", "strings")), - "'name' must be passed as a single string. Got a string vector of length 3 instead." + "'name' must be a single string. Got a vector of length 3." ) close(data$client) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops_magrittr_pipe.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R similarity index 95% rename from R/rdeephaven/inst/tests/testthat/test_table_ops_magrittr_pipe.R rename to R/rdeephaven/inst/tests/testthat/test_table_ops.R index 13fa7be38b2..c16f5b92c50 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops_magrittr_pipe.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -140,6 +140,45 @@ test_that("select behaves as expected", { close(data$client) }) +test_that("select with base pipe behaves as expected", { + data <- setup() + + new_tb1 <- data$df1 |> + dplyr::select(string_col) + new_th1 <- data$th1 |> + select("string_col") + expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) + + new_tb2 <- data$df2 |> + dplyr::select(col2, col3) + new_th2 <- data$th2 |> + select(c("col2", "col3")) + expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) + + new_tb3 <- data$df3 |> + dplyr::select(X1, X2) |> + rename(first_col = X1) + new_th3 <- data$th3 |> + select(c("first_col = X1", "X2")) + expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) + + new_tb4 <- data$df4 |> + dplyr::select(int_col) |> + mutate(new_col = int_col + 1, .keep = "none") + new_th4 <- data$th4 |> + select("new_col = int_col + 1") + expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) + + new_tb5 <- data$df5 |> + mutate(Number3 = Number1 * Number2) |> + dplyr::select(X, Number3) + new_th5 <- data$th5 |> + select(c("X", "Number3 = Number1 * Number2")) + expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) + + close(data$client) +}) + test_that("view behaves as expected", { data <- setup() diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R b/R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R deleted file mode 100644 index f6f32a14431..00000000000 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops_base_pipe.R +++ /dev/null @@ -1,840 +0,0 @@ -library(testthat) -library(dplyr) -library(rdeephaven) - -setup <- function() { - df1 <- data.frame( - string_col = c("I", "am", "a", "string", "column"), - int_col = c(0, 1, 2, 3, 4), - dbl_col = c(1.65, 3.1234, 100000.5, 543.234567, 0.00) - ) - - df2 <- data.frame( - col1 = rep(3.14, 100), - col2 = rep("hello!", 100), - col3 = rnorm(100) - ) - - df3 <- data.frame(matrix(rnorm(10 * 1000), nrow = 10)) - - df4 <- data.frame( - time_col = seq.POSIXt(as.POSIXct(Sys.Date()), as.POSIXct(Sys.Date() + 30), by = "1 sec")[250000], - bool_col = sample(c(TRUE, FALSE), 250000, TRUE), - int_col = sample(0:10000, 250000, TRUE) - ) - - df5 <- data.frame( - X = c("A", "B", "A", "C", "B", "A", "B", "B", "C"), - Y = c("M", "N", "O", "N", "P", "M", "O", "P", "M"), - Number1 = c(100, -44, 49, 11, -66, 50, 29, 18, -70), - Number2 = c(-55, 76, 20, 130, 230, -50, 73, 137, 214) - ) - - df6 <- data.frame( - X = c("B", "C", "B", "A", "A", "C", "B", "C", "B", "A"), - Y = c("N", "N", "M", "P", "O", "P", "O", "N", "O", "O"), - Number1 = c(55, 72, 86, -45, 1, 0, 345, -65, 99, -5), - Number2 = c(76, 4, -6, 34, 12, -76, 45, -5, 34, 6) - ) - - # set up client - client <- connect(target = "localhost:10000") - - # move dataframes to server and get TableHandles for testing - th1 <- import_table(client, df1) - th2 <- import_table(client, df2) - th3 <- import_table(client, df3) - th4 <- import_table(client, df4) - th5 <- import_table(client, df5) - th6 <- import_table(client, df6) - - return(list( - "client" = client, - "df1" = df1, "df2" = df2, "df3" = df3, "df4" = df4, "df5" = df5, "df6" = df6, - "th1" = th1, "th2" = th2, "th3" = th3, "th4" = th4, "th5" = th5, "th6" = th6 - )) -} - -##### TESTING GOOD INPUTS ##### - -test_that("merge behaves as expected", { - data <- setup() - - new_df1 <- rbind(data$df5) - new_th1 <- merge(data$th5) - expect_equal(as.data.frame(new_th1), new_df1) - - new_df2 <- rbind(data$df5, data$df6) - new_th2 <- merge(data$th5, data$th6) - expect_equal(as.data.frame(new_th2), new_df2) - - new_df3 <- rbind(data$df5, data$df6, data$df6, data$df5) - new_th3 <- merge(data$th5, data$th6, data$th6, data$th5) - expect_equal(as.data.frame(new_th3), new_df3) - - new_th4 <- merge(data$th5, NULL) - expect_equal(as.data.frame(new_th4), new_df1) - - new_th5 <- merge(NULL, data$th5) - expect_equal(as.data.frame(new_th5), new_df1) - - new_th6 <- merge(c(data$th5, data$th6)) - expect_equal(as.data.frame(new_th6), new_df2) - - new_th7 <- merge(NULL, c(data$th5, data$th6)) - expect_equal(as.data.frame(new_th7), new_df2) - - new_th8 <- merge(c(data$th5, data$th6), NULL) - expect_equal(as.data.frame(new_th8), new_df2) - - new_th9 <- merge(data$th5, c(data$th6, data$th6, data$th5)) - expect_equal(as.data.frame(new_th9), new_df3) - - new_th10 <- merge(c(data$th5, data$th6, data$th6), data$th5) - expect_equal(as.data.frame(new_th10), new_df3) - - new_th11 <- merge(c(data$th5, data$th6), c(data$th6, data$th5)) - expect_equal(as.data.frame(new_th11), new_df3) - - new_th12 <- merge(c(data$th5, data$th6, data$th6, data$th5)) - expect_equal(as.data.frame(new_th12), new_df3) - -}) - -test_that("select behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::select(string_col) - new_th1 <- data$th1 |> - select("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::select(col2, col3) - new_th2 <- data$th2 |> - select(c("col2", "col3")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::select(X1, X2) |> - rename(first_col = X1) - new_th3 <- data$th3 |> - select(c("first_col = X1", "X2")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::select(int_col) |> - mutate(new_col = int_col + 1, .keep = "none") - new_th4 <- data$th4 |> - select("new_col = int_col + 1") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - mutate(Number3 = Number1 * Number2) |> - dplyr::select(X, Number3) - new_th5 <- data$th5 |> - select(c("X", "Number3 = Number1 * Number2")) - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - close(data$client) -}) - -test_that("view behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::select(string_col) - new_th1 <- data$th1 |> - view("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::select(col2, col3) - new_th2 <- data$th2 |> - view(c("col2", "col3")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::select(X1, X2) |> - rename(first_col = X1) - new_th3 <- data$th3 |> - view(c("first_col = X1", "X2")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::select(int_col) |> - mutate(new_col = int_col + 1, .keep = "none") - new_th4 <- data$th4 |> - view("new_col = int_col + 1") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - mutate(Number3 = Number1 * Number2) |> - dplyr::select(X, Number3) - new_th5 <- data$th5 |> - view(c("X", "Number3 = Number1 * Number2")) - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - close(data$client) -}) - -test_that("update behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - mutate(dbl_col_again = dbl_col) - new_th1 <- data$th1 |> - update("dbl_col_again = dbl_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - mutate(col4 = col3 * 2) - new_th2 <- data$th2 |> - update("col4 = col3 * 2") - expect_equal(as.data.frame(new_tb2), as.data.frame(new_th2)) - - new_tb3 <- data$df3 |> - mutate(X1001 = X1000, X1002 = X1001) - new_th3 <- data$th3 |> - update(c("X1001 = X1000", "X1002 = X1001")) - expect_equal(as.data.frame(new_tb3), as.data.frame(new_th3)) - - new_tb4 <- data$df4 |> - mutate(new_col = sqrt(3 * int_col)) - new_th4 <- data$th4 |> - update("new_col = sqrt(3 * int_col)") - expect_equal(as.data.frame(new_tb4), as.data.frame(new_th4)) - - new_tb5 <- data$df5 |> - mutate(Number3 = Number1 + Number2) - new_th5 <- data$th5 |> - update("Number3 = Number1 + Number2") - expect_equal(as.data.frame(new_tb5), as.data.frame(new_th5)) - - close(data$client) -}) - -test_that("update_view behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - mutate(dbl_col_again = dbl_col) - new_th1 <- data$th1 |> - update_view("dbl_col_again = dbl_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - mutate(col4 = col3 * 2) - new_th2 <- data$th2 |> - update_view("col4 = col3 * 2") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - mutate(X1001 = X1000, X1002 = X1001) - new_th3 <- data$th3 |> - update_view(c("X1001 = X1000", "X1002 = X1001")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - mutate(new_col = sqrt(3 * int_col)) - new_th4 <- data$th4 |> - update_view("new_col = sqrt(3 * int_col)") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - mutate(Number3 = Number1 + Number2) - new_th5 <- data$th5 |> - update_view("Number3 = Number1 + Number2") - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - close(data$client) -}) - -test_that("drop_columns behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::select(-string_col) - new_th1 <- data$th1 |> - drop_columns("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::select(-c(col1, col2)) - new_th2 <- data$th2 |> - drop_columns(c("col1", "col2")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - dplyr::select(-paste0("X", seq(2, 1000))) - new_th3 <- data$th3 |> - drop_columns(paste0("X", seq(2, 1000))) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - close(data$client) -}) - -test_that("where behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - filter(int_col < 3) - new_th1 <- data$th1 |> - where("int_col < 3") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - filter(col2 == "hello!") - new_th2 <- data$th2 |> - where("col2 == `hello!`") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - filter(X1 - X4 + X8 + X32 - 2 * X5 >= 0) - new_th3 <- data$th3 |> - where("X1 - X4 + X8 + X32 - 2*X5 >= 0") - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - close(data$client) -}) - -test_that("group_by and ungroup behave as expected", { - data <- setup() - - # There is not a clean analog to group_by() in dplyr, so we evaluate - # correctness by evaluating that these functions behave as inverses. - # Easiest when grouping columns are first, otherwise we must also reorder. - - new_th1 <- data$th1 |> - group_by("string_col") |> - ungroup() |> - sort("string_col") - expect_equal(as.data.frame(new_th1), as.data.frame(data$th1 |> sort("string_col"))) - - new_th3 <- data$th3 |> - group_by(c("X1", "X2", "X3", "X4", "X5")) |> - ungroup() |> - sort(c("X1", "X2", "X3", "X4", "X5")) - expect_equal(as.data.frame(new_th3), as.data.frame(data$th3 |> sort(c("X1", "X2", "X3", "X4", "X5")))) - - new_th5 <- data$th5 |> - group_by("X") |> - ungroup() |> - sort("X") - expect_equal(as.data.frame(new_th5), as.data.frame(data$th5 |> sort("X"))) - - new_th6 <- data$th6 |> - group_by(c("X", "Y")) |> - ungroup() |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th6), as.data.frame(data$th6 |> sort(c("X", "Y")))) - - close(data$client) -}) - -test_that("first_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), first)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - first_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), first)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - first_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("last_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), last)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - last_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), last)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - last_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("head_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::group_by(X) |> - slice_head(n = 2) - new_th1 <- data$th5 |> - head_by(2, "X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - slice_head(n = 2) - new_th2 <- data$th5 |> - head_by(2, c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("tail_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::group_by(X) |> - slice_tail(n = 2) - new_th1 <- data$th5 |> - tail_by(2, "X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - slice_tail(n = 2) - new_th2 <- data$th5 |> - tail_by(2, c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("min_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(int_col) |> - summarise(across(everything(), min)) - new_th1 <- data$th1 |> - min_by("int_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col2) |> - summarise(across(everything(), min)) - new_th2 <- data$th2 |> - min_by("col2") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) |> - dplyr::group_by(bool_col1, bool_col2) |> - summarise(across(everything(), min)) |> - arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same - new_th3 <- data$th3 |> - update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) |> - min_by(c("bool_col1", "bool_col2")) |> - sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(across(everything(), min)) |> - arrange(bool_col) - new_th4 <- data$th4 |> - min_by("bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - close(data$client) -}) - -test_that("max_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - dplyr::group_by(int_col) |> - summarise(across(everything(), max)) - new_th1 <- data$th1 |> - max_by("int_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - dplyr::group_by(col2) |> - summarise(across(everything(), max)) - new_th2 <- data$th2 |> - max_by("col2") - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - mutate(bool_col1 = X1 >= 0, bool_col2 = X2 >= 0) |> - dplyr::group_by(bool_col1, bool_col2) |> - summarise(across(everything(), max)) |> - arrange(bool_col1, bool_col2) # need to sort because resulting row orders are not the same - new_th3 <- data$th3 |> - update(c("bool_col1 = X1 >= 0", "bool_col2 = X2 >= 0")) |> - max_by(c("bool_col1", "bool_col2")) |> - sort(c("bool_col1", "bool_col2")) # need to sort because resulting row orders are not the same - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - dplyr::group_by(bool_col) |> - summarise(across(everything(), max)) |> - arrange(bool_col) - new_th4 <- data$th4 |> - max_by("bool_col") |> - sort("bool_col") - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - close(data$client) -}) - -test_that("sum_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), sum)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - sum_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), sum)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - sum_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("abs_sum_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - mutate(Number1 = abs(Number1), Number2 = abs(Number2)) |> - dplyr::group_by(X) |> - summarise(across(everything(), sum)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - abs_sum_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - mutate(Number1 = abs(Number1), Number2 = abs(Number2)) |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), sum)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - abs_sum_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("avg_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), mean)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - avg_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), mean)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - avg_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("w_avg_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - mutate(weights = Number1 * Number2) |> - dplyr::group_by(X) |> - summarise( - Number1 = weighted.mean(Number1, weights), - Number2 = weighted.mean(Number2, weights) - ) - new_th1 <- data$th5 |> - drop_columns("Y") |> - update("weights = Number1 * Number2") |> - w_avg_by("weights", "X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - mutate(weights = Number1 * Number2) |> - dplyr::group_by(X, Y) |> - summarise( - Number1 = weighted.mean(Number1, weights), - Number2 = weighted.mean(Number2, weights) - ) |> - arrange(X, Y) - new_th2 <- data$th5 |> - update("weights = Number1 * Number2") |> - w_avg_by("weights", c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("median_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), median)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - median_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), median)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - median_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("var_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), var)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - var_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), var)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - var_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("std_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), sd)) - new_th1 <- data$th5 |> - drop_columns("Y") |> - std_by("X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - dplyr::group_by(X, Y) |> - summarise(across(everything(), sd)) |> - arrange(X, Y) - new_th2 <- data$th5 |> - std_by(c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("percentile_by behaves as expected", { - data <- setup() - - # There is not a clean analog to `percentile_by` in dplyr, - # so we construct these data frames directly. - - new_df1 <- data.frame( - X = c("A", "B", "C"), - Number1 = c(50, -44, -70), - Number2 = c(-50, 76, 130) - ) - new_th1 <- data$th5 |> - drop_columns("Y") |> - percentile_by(0.4, "X") - expect_equal(as.data.frame(new_th1), new_df1) - - new_df2 <- data.frame( - X = c("A", "B", "A", "C", "B", "B", "C"), - Y = c("M", "N", "O", "N", "P", "O", "M"), - Number1 = c(50, -44, 49, 11, -66, 29, -70), - Number2 = c(-55, 76, 20, 130, 137, 73, 214) - ) - new_th2 <- data$th5 |> - percentile_by(0.4, c("X", "Y")) - expect_equal(as.data.frame(new_th2), new_df2) - - - close(data$client) -}) - -test_that("count_by behaves as expected", { - data <- setup() - - new_tb1 <- data$df5 |> - count(X) - new_th1 <- data$th5 |> - count_by("n", "X") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df5 |> - count(X, Y) - new_th2 <- data$th5 |> - count_by("n", c("X", "Y")) |> - sort(c("X", "Y")) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - close(data$client) -}) - -test_that("sort behaves as expected", { - data <- setup() - - new_tb1 <- data$df1 |> - arrange(dbl_col) - new_th1 <- data$th1 |> - sort("dbl_col") - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - new_tb2 <- data$df2 |> - arrange(desc(col3)) - new_th2 <- data$th2 |> - sort("col3", descending = TRUE) - expect_equal(as.data.frame(new_th2), as.data.frame(new_tb2)) - - new_tb3 <- data$df3 |> - arrange(X1, X2, X3, X4, X5) - new_th3 <- data$th3 |> - sort(c("X1", "X2", "X3", "X4", "X5")) - expect_equal(as.data.frame(new_th3), as.data.frame(new_tb3)) - - new_tb4 <- data$df4 |> - arrange(desc(bool_col), desc(int_col)) - new_th4 <- data$th4 |> - sort(c("bool_col", "int_col"), descending = TRUE) - expect_equal(as.data.frame(new_th4), as.data.frame(new_tb4)) - - new_tb5 <- data$df5 |> - arrange(X, desc(Y), Number1) - new_th5 <- data$th5 |> - sort(c("X", "Y", "Number1"), descending = c(FALSE, TRUE, FALSE)) - expect_equal(as.data.frame(new_th5), as.data.frame(new_tb5)) - - close(data$client) -}) - -test_that("cross_join behaves as expected", { - data <- setup() - - new_th1 <- data$th5 |> - cross_join(data$th6, - columns_to_match = character(), - columns_to_add = c("X_y = X", "Y_y = Y", "Number1_y = Number1", "Number2_y = Number2") - ) - new_tb1 <- data$df5 |> - dplyr::cross_join(data$df6) |> - rename( - X = X.x, Y = Y.x, Number1 = Number1.x, Number2 = Number2.x, - X_y = X.y, Y_y = Y.y, Number1_y = Number1.y, Number2_y = Number2.y - ) - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - close(data$client) -}) - -test_that("natural_join behaves as expected", { - data <- setup() - - new_th2 <- data$th6 |> - drop_columns("Y") |> - avg_by("X") - new_th1 <- data$th5 |> - natural_join(new_th2, - columns_to_match = "X", - columns_to_add = c("Number3 = Number1", "Number4 = Number2") - ) - - new_tb2 <- data$df6 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), mean)) - new_tb1 <- data$df5 |> - left_join(new_tb2, by = "X") |> - rename( - Number1 = Number1.x, Number2 = Number2.x, - Number3 = Number1.y, Number4 = Number2.y - ) - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - close(data$client) -}) - -# TODO: Verify that inner_join is the analog of exact_join -test_that("exact_join behaves as expected", { - data <- setup() - - new_th2 <- data$th6 |> - drop_columns("Y") |> - avg_by("X") - new_th1 <- data$th5 |> - exact_join(new_th2, - columns_to_match = "X", - columns_to_add = c("Number3 = Number1", "Number4 = Number2") - ) - - new_tb2 <- data$df6 |> - dplyr::select(-Y) |> - dplyr::group_by(X) |> - summarise(across(everything(), mean)) - new_tb1 <- data$df5 |> - inner_join(new_tb2, by = "X") |> - rename(Number1 = Number1.x, Number2 = Number2.x, Number3 = Number1.y, Number4 = Number2.y) - expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) - - close(data$client) -}) From d42b76fb5bf974de531ce7914dc133398712af24 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 9 Aug 2023 09:49:55 -0500 Subject: [PATCH 50/73] Refactor import_table to as_dh_table with generics --- R/rdeephaven/NAMESPACE | 4 +- R/rdeephaven/R/client_wrapper.R | 80 +++++++++---------- R/rdeephaven/R/exports.R | 2 +- .../inst/tests/testthat/test_agg_by.R | 12 +-- .../inst/tests/testthat/test_client_wrapper.R | 78 ++++++++---------- .../testthat/test_table_handle_wrapper.R | 8 +- .../inst/tests/testthat/test_table_ops.R | 12 +-- 7 files changed, 93 insertions(+), 103 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index d0312a4daf7..a0c34ddda94 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -21,6 +21,7 @@ exportMethods(abs_sum_by) exportMethods(agg_by) exportMethods(as.data.frame) exportMethods(as_arrow_table) +exportMethods(as_dh_table) exportMethods(as_record_batch_reader) exportMethods(as_tibble) exportMethods(avg_by) @@ -36,7 +37,6 @@ exportMethods(first_by) exportMethods(group_by) exportMethods(head) exportMethods(head_by) -exportMethods(import_table) exportMethods(is_static) exportMethods(last_by) exportMethods(max_by) @@ -64,7 +64,9 @@ exportMethods(w_avg_by) exportMethods(where) import(Rcpp) importFrom(Rcpp,evalCpp) +importFrom(arrow,RecordBatchReader) importFrom(arrow,RecordBatchStreamReader) +importFrom(arrow,Table) importFrom(arrow,arrow_table) importFrom(arrow,as_arrow_table) importFrom(arrow,as_record_batch_reader) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 36f35745453..5869815683f 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -103,33 +103,11 @@ setMethod( ) ### HELPER FUNCTIONS ### -# These functions return RC objects returned by Rcpp without wrapping them in S4 check_for_table <- function(client, name) { return(client@.internal_rcpp_object$check_for_table(name)) } -rbr_to_dh_table <- function(client, rbr) { - ptr <- client@.internal_rcpp_object$new_arrow_array_stream_ptr() - rbr$export_to_c(ptr) - return(client@.internal_rcpp_object$new_table_from_arrow_array_stream_ptr(ptr)) -} - -arrow_to_dh_table <- function(client, arrow_tbl) { - rbr <- as_record_batch_reader(arrow_tbl) - return(rbr_to_dh_table(client, rbr)) -} - -tibble_to_dh_table <- function(client, tibbl) { - arrow_tbl <- arrow_table(tibbl) - return(arrow_to_dh_table(client, arrow_tbl)) -} - -df_to_dh_table <- function(client, data_frame) { - arrow_tbl <- arrow_table(data_frame) - return(arrow_to_dh_table(client, arrow_tbl)) -} - ### USER-FACING METHODS ### setGeneric( @@ -191,34 +169,52 @@ setMethod( ) setGeneric( - "import_table", + "as_dh_table", function(client_instance, table_object) { - return(standardGeneric("import_table")) + return(standardGeneric("as_dh_table")) }, signature = c("client_instance", "table_object") ) #' @export setMethod( - "import_table", - signature = c(client_instance = "Client"), + "as_dh_table", + signature = c(client_instance = "Client", table_object = "RecordBatchReader"), function(client_instance, table_object) { - table_object_class <- class(table_object) - - if (table_object_class[[1]] == "data.frame") { - rcpp_dh_table <- df_to_dh_table(client_instance, table_object) - } else if (table_object_class[[1]] == "tbl_df") { - rcpp_dh_table <- tibble_to_dh_table(client_instance, table_object) - } else if (table_object_class[[1]] == "RecordBatchReader") { - rcpp_dh_table <- rbr_to_dh_table(client_instance, table_object) - } else if ((length(table_object_class) == 4 && - table_object_class[[1]] == "Table" && - table_object_class[[3]] == "ArrowObject")) { - rcpp_dh_table <- arrow_to_dh_table(client_instance, table_object) - } else { - stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class ", table_object_class[[1]], ".")) - } - return(new("TableHandle", .internal_rcpp_object = rcpp_dh_table)) + ptr <- client_instance@.internal_rcpp_object$new_arrow_array_stream_ptr() + table_object$export_to_c(ptr) + return( + new("TableHandle", + .internal_rcpp_object = client_instance@.internal_rcpp_object$new_table_from_arrow_array_stream_ptr(ptr)) + ) + } +) + +# TODO: This may not be correct +#' @export +setMethod( + "as_dh_table", + signature = c(client_instance = "Client", table_object = "Table"), + function(client_instance, table_object) { + return(as_dh_table(client_instance, as_record_batch_reader(table_object))) + } +) + +#' @export +setMethod( + "as_dh_table", + signature = c(client_instance = "Client", table_object = "tbl_df"), + function(client_instance, table_object) { + return(as_dh_table(client_instance, arrow_table(table_object))) + } +) + +#' @export +setMethod( + "as_dh_table", + signature = c(client_instance = "Client", table_object = "data.frame"), + function(client_instance, table_object) { + return(as_dh_table(client_instance, arrow_table(table_object))) } ) diff --git a/R/rdeephaven/R/exports.R b/R/rdeephaven/R/exports.R index 4797e402113..5809ae84b61 100644 --- a/R/rdeephaven/R/exports.R +++ b/R/rdeephaven/R/exports.R @@ -3,7 +3,7 @@ #' @importFrom Rcpp evalCpp #' #' @importFrom magrittr %>% -#' @importFrom arrow arrow_table as_arrow_table as_record_batch_reader RecordBatchStreamReader +#' @importFrom arrow arrow_table as_arrow_table as_record_batch_reader Table RecordBatchReader RecordBatchStreamReader #' @importFrom dplyr as_tibble loadModule("DeephavenInternalModule", TRUE) diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index fc9e3b11bde..259c65d86f2 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -41,12 +41,12 @@ setup <- function() { client <- connect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- import_table(client, df1) - th2 <- import_table(client, df2) - th3 <- import_table(client, df3) - th4 <- import_table(client, df4) - th5 <- import_table(client, df5) - th6 <- import_table(client, df6) + th1 <- as_dh_table(client, df1) + th2 <- as_dh_table(client, df2) + th3 <- as_dh_table(client, df3) + th4 <- as_dh_table(client, df4) + th5 <- as_dh_table(client, df5) + th6 <- as_dh_table(client, df6) return(list( "client" = client, diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 09070d39546..a8c58a3551c 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -36,59 +36,59 @@ test_that("client connection works in the simple case of anonymous authenticatio # All of the following tests assume the correctness of new(...) to make the connection. -test_that("import_table does not fail with data frame inputs of simple column types", { +test_that("as_dh_table does not fail with data frame inputs of simple column types", { data <- setup() client <- connect(target = "localhost:10000") - expect_no_error(import_table(client, data$df1)) - expect_no_error(import_table(client, data$df2)) - expect_no_error(import_table(client, data$df3)) - expect_no_error(import_table(client, data$df4)) + expect_no_error(as_dh_table(client, data$df1)) + expect_no_error(as_dh_table(client, data$df2)) + expect_no_error(as_dh_table(client, data$df3)) + expect_no_error(as_dh_table(client, data$df4)) close(client) }) -test_that("import_table does not fail with tibble inputs of simple column types", { +test_that("as_dh_table does not fail with tibble inputs of simple column types", { data <- setup() client <- connect(target = "localhost:10000") - expect_no_error(import_table(client, as_tibble(data$df1))) - expect_no_error(import_table(client, as_tibble(data$df2))) - expect_no_error(import_table(client, as_tibble(data$df3))) - expect_no_error(import_table(client, as_tibble(data$df4))) + expect_no_error(as_dh_table(client, as_tibble(data$df1))) + expect_no_error(as_dh_table(client, as_tibble(data$df2))) + expect_no_error(as_dh_table(client, as_tibble(data$df3))) + expect_no_error(as_dh_table(client, as_tibble(data$df4))) close(client) }) -test_that("import_table does not fail with arrow table inputs of simple column types", { +test_that("as_dh_table does not fail with arrow table inputs of simple column types", { data <- setup() client <- connect(target = "localhost:10000") - expect_no_error(import_table(client, as_arrow_table(data$df1))) - expect_no_error(import_table(client, as_arrow_table(data$df2))) - expect_no_error(import_table(client, as_arrow_table(data$df3))) - expect_no_error(import_table(client, as_arrow_table(data$df4))) + expect_no_error(as_dh_table(client, as_arrow_table(data$df1))) + expect_no_error(as_dh_table(client, as_arrow_table(data$df2))) + expect_no_error(as_dh_table(client, as_arrow_table(data$df3))) + expect_no_error(as_dh_table(client, as_arrow_table(data$df4))) close(client) }) -test_that("import_table does not fail with record batch reader inputs of simple column types", { +test_that("as_dh_table does not fail with record batch reader inputs of simple column types", { data <- setup() client <- connect(target = "localhost:10000") - expect_no_error(import_table(client, as_record_batch_reader(data$df1))) - expect_no_error(import_table(client, as_record_batch_reader(data$df2))) - expect_no_error(import_table(client, as_record_batch_reader(data$df3))) - expect_no_error(import_table(client, as_record_batch_reader(data$df4))) + expect_no_error(as_dh_table(client, as_record_batch_reader(data$df1))) + expect_no_error(as_dh_table(client, as_record_batch_reader(data$df2))) + expect_no_error(as_dh_table(client, as_record_batch_reader(data$df3))) + expect_no_error(as_dh_table(client, as_record_batch_reader(data$df4))) close(client) }) -# The following tests additionally assume the correctness of import_table(...) AND table_handle$bind_to_variable(), +# The following tests additionally assume the correctness of as_dh_table(...) AND table_handle$bind_to_variable(), # as we have to create data, push it to the server, and name it in order to test open_table(). # Additionally, we assume the correctness of table_handle$to_data_frame() to make concrete comparisons. @@ -97,19 +97,19 @@ test_that("open_table opens the correct table from the server using %>%", { client <- connect(target = "localhost:10000") - th1 <- import_table(client, data$df1) + th1 <- as_dh_table(client, data$df1) th1 %>% bind_to_variable("table1") expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) - th2 <- import_table(client, data$df2) + th2 <- as_dh_table(client, data$df2) th2 %>% bind_to_variable("table2") expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) - th3 <- import_table(client, data$df3) + th3 <- as_dh_table(client, data$df3) th3 %>% bind_to_variable("table3") expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) - th4 <- import_table(client, data$df4) + th4 <- as_dh_table(client, data$df4) th4 %>% bind_to_variable("table4") expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) @@ -121,19 +121,19 @@ test_that("open_table opens the correct table from the server using |>", { client <- connect(target = "localhost:10000") - th1 <- import_table(client, data$df1) + th1 <- as_dh_table(client, data$df1) th1 |> bind_to_variable("table1") expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) - th2 <- import_table(client, data$df2) + th2 <- as_dh_table(client, data$df2) th2 |> bind_to_variable("table2") expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) - th3 <- import_table(client, data$df3) + th3 <- as_dh_table(client, data$df3) th3 |> bind_to_variable("table3") expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) - th4 <- import_table(client, data$df4) + th4 <- as_dh_table(client, data$df4) th4 |> bind_to_variable("table4") expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) @@ -229,29 +229,21 @@ test_that("connect fails nicely with bad inputs", { }) -test_that("import_table fails nicely with bad inputs", { +test_that("as_dh_table fails nicely with bad inputs", { library(datasets) client <- connect(target = "localhost:10000") - expect_error( - import_table(client, 12345), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class numeric." - ) - expect_error( - import_table(client, "hello!"), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class character." - ) + expect_error(as_dh_table(client, 12345)) + + expect_error(as_dh_table(client, "hello!")) # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. data(iris) - expect_error(import_table(client, iris)) + expect_error(as_dh_table(client, iris)) data(HairEyeColor) - expect_error( - import_table(client, HairEyeColor), - "'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader. Got an object of class table." - ) + expect_error(as_dh_table(client, HairEyeColor)) close(client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index a03da33bce0..b2eef6cbb61 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -26,10 +26,10 @@ setup <- function() { client <- connect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- import_table(client, df1) - th2 <- import_table(client, df2) - th3 <- import_table(client, df3) - th4 <- import_table(client, df4) + th1 <- as_dh_table(client, df1) + th2 <- as_dh_table(client, df2) + th3 <- as_dh_table(client, df3) + th4 <- as_dh_table(client, df4) # time table to test is_static() th5 <- time_table(client, 1000000000) %>% update("X = ii") diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index c16f5b92c50..754263e5d7a 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -41,12 +41,12 @@ setup <- function() { client <- connect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- import_table(client, df1) - th2 <- import_table(client, df2) - th3 <- import_table(client, df3) - th4 <- import_table(client, df4) - th5 <- import_table(client, df5) - th6 <- import_table(client, df6) + th1 <- as_dh_table(client, df1) + th2 <- as_dh_table(client, df2) + th3 <- as_dh_table(client, df3) + th4 <- as_dh_table(client, df4) + th5 <- as_dh_table(client, df5) + th6 <- as_dh_table(client, df6) return(list( "client" = client, From 78bbe2469d6233a781801432e93c736fb23e41dd Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 9 Aug 2023 11:20:22 -0500 Subject: [PATCH 51/73] Applying more code review --- R/rdeephaven/R/client_wrapper.R | 13 +++++------ .../inst/tests/testthat/test_client_wrapper.R | 23 ++++++++----------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 5869815683f..58d75230472 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -121,7 +121,7 @@ setGeneric( #' @export setMethod( "open_table", - signature = c(client_instance = "Client"), + signature = c(client_instance = "Client", name = "character"), function(client_instance, name) { verify_string("name", name, TRUE) if (!check_for_table(client_instance, name)) { @@ -142,7 +142,7 @@ setGeneric( #' @export setMethod( "empty_table", - signature = c(client_instance = "Client"), + signature = c(client_instance = "Client", size = "numeric"), function(client_instance, size) { verify_positive_int("size", size, TRUE) return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$empty_table(size))) @@ -151,16 +151,16 @@ setMethod( setGeneric( "time_table", - function(client_instance, ...) { + function(client_instance, period, ...) { return(standardGeneric("time_table")) }, - signature = "client_instance" + signature = c("client_instance", "period") ) #' @export setMethod( "time_table", - signature = c(client_instance = "Client"), + signature = c(client_instance = "Client", period = "numeric"), function(client_instance, period, start_time = 0) { verify_any_int("period", period, TRUE) verify_any_int("start_time", start_time, TRUE) @@ -190,7 +190,6 @@ setMethod( } ) -# TODO: This may not be correct #' @export setMethod( "as_dh_table", @@ -229,7 +228,7 @@ setGeneric( #' @export setMethod( "run_script", - signature = c(client_instance = "Client"), + signature = c(client_instance = "Client", script = "character"), function(client_instance, script) { verify_string("script", script, TRUE) client_instance@.internal_rcpp_object$run_script(script) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index a8c58a3551c..bcde8db7017 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -34,8 +34,6 @@ test_that("client connection works in the simple case of anonymous authenticatio }) -# All of the following tests assume the correctness of new(...) to make the connection. - test_that("as_dh_table does not fail with data frame inputs of simple column types", { data <- setup() @@ -88,9 +86,9 @@ test_that("as_dh_table does not fail with record batch reader inputs of simple c close(client) }) -# The following tests additionally assume the correctness of as_dh_table(...) AND table_handle$bind_to_variable(), +# The following tests assume the correctness of as_dh_table(...) AND bind_to_variable(), # as we have to create data, push it to the server, and name it in order to test open_table(). -# Additionally, we assume the correctness of table_handle$to_data_frame() to make concrete comparisons. +# Additionally, we assume the correctness of as.data.frame() to make concrete comparisons. test_that("open_table opens the correct table from the server using %>%", { data <- setup() @@ -234,16 +232,15 @@ test_that("as_dh_table fails nicely with bad inputs", { client <- connect(target = "localhost:10000") - expect_error(as_dh_table(client, 12345)) - - expect_error(as_dh_table(client, "hello!")) + expect_error(as_dh_table(client, 12345), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"numeric\"’")) + expect_error(as_dh_table(client, "hello!"), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"character\"’")) # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. data(iris) expect_error(as_dh_table(client, iris)) data(HairEyeColor) - expect_error(as_dh_table(client, HairEyeColor)) + expect_error(as_dh_table(client, HairEyeColor), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"table\"’")) close(client) }) @@ -252,7 +249,7 @@ test_that("open_table fails nicely with bad inputs", { client <- connect(target = "localhost:10000") expect_error(open_table(client, ""), "The table '' does not exist on the server.") - expect_error(open_table(client, 12345), "'name' must be a single string. Got an object of class numeric.") + expect_error(open_table(client, 12345), cat("unable to find an inherited method for function ‘open_table’ for signature ‘\"Client\", \"numeric\"’")) expect_error(open_table(client, c("I", "am", "string")), "'name' must be a single string. Got a vector of length 3.") close(client) @@ -264,7 +261,7 @@ test_that("empty_table fails nicely with bad inputs", { expect_error(empty_table(client, 0), "'size' must be a positive integer. Got 'size' = 0.") expect_error(empty_table(client, -3), "'size' must be a positive integer. Got 'size' = -3.") expect_error(empty_table(client, 1.2345), "'size' must be an integer. Got 'size' = 1.2345.") - expect_error(empty_table(client, "hello!"), "'size' must be a single numeric. Got an object of class character.") + expect_error(empty_table(client, "hello!"), cat("unable to find an inherited method for function ‘empty_table’ for signature ‘\"Client\", \"character\"’")) expect_error(empty_table(client, c(1, 2, 3, 4)), "'size' must be a single numeric. Got a vector of length 4.") close(client) @@ -277,8 +274,8 @@ test_that("time_table fails nicely with bad inputs", { expect_error(time_table(client, 1000, 1.23), "'start_time' must be an integer. Got 'start_time' = 1.23.") expect_error(time_table(client, c(1, 2, 3), 1000), "'period' must be a single numeric. Got a vector of length 3.") expect_error(time_table(client, 1000, c(1, 2, 3)), "'start_time' must be a single numeric. Got a vector of length 3.") - expect_error(time_table(client, "hello!", 1000), "'period' must be a single numeric. Got an object of class character.") - expect_error(time_table(client, 1000, "hello!"), "'start_time' must be a single numeric. Got an object of class character.") + expect_error(time_table(client, "hello!", 1000), cat("unable to find an inherited method for function ‘time_table’ for signature ‘\"Client\", \"character\", \"numeric\"’")) + expect_error(time_table(client, 1000, "hello!"), cat("unable to find an inherited method for function ‘time_table’ for signature ‘\"Client\", \"numeric\", \"character\"’")) close(client) }) @@ -286,7 +283,7 @@ test_that("time_table fails nicely with bad inputs", { test_that("run_script fails nicely with bad input types", { client <- connect(target = "localhost:10000") - expect_error(run_script(client, 12345), "'script' must be a single string. Got an object of class numeric.") + expect_error(run_script(client, 12345), cat("unable to find an inherited method for function ‘run_script’ for signature ‘\"Client\", \"numeric\"’")) expect_error(run_script(client, c("I", "am", "a", "string")), "'script' must be a single string. Got a vector of length 4.") close(client) From a7bef487df71140fdaeffb593b171617806fd58a Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 9 Aug 2023 11:37:51 -0500 Subject: [PATCH 52/73] Applying even more code review --- R/rdeephaven/R/table_handle_wrapper.R | 2 +- .../inst/tests/testthat/test_table_handle_wrapper.R | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 66b81dab20b..b4ddd46d5e8 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -114,7 +114,7 @@ setGeneric( #' @export setMethod( "bind_to_variable", - signature = c(table_handle_instance = "TableHandle"), + signature = c(table_handle_instance = "TableHandle", name = "character"), function(table_handle_instance, name) { verify_string("name", name, TRUE) table_handle_instance@.internal_rcpp_object$bind_to_variable(name) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index b2eef6cbb61..d7df27382c6 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -171,7 +171,7 @@ test_that("bind_to_variable fails nicely on bad inputs", { expect_error( data$th1 %>% bind_to_variable(12345), - "'name' must be a single string. Got an object of class numeric." + cat("unable to find an inherited method for function ‘bind_to_variable’ for signature ‘\"TableHandle\", \"numeric\"’") ) expect_error( @@ -181,12 +181,12 @@ test_that("bind_to_variable fails nicely on bad inputs", { expect_error( data$th1 %>% bind_to_variable(data$df1), - "'name' must be a single string. Got a vector of length 3." + cat("unable to find an inherited method for function 'bind_to_variable' for signature '\"TableHandle\", \"data.frame\"'") ) expect_error( data$th1 %>% bind_to_variable(list("list", "of", "strings")), - "'name' must be a single string. Got a vector of length 3." + cat("unable to find an inherited method for function ‘bind_to_variable’ for signature ‘\"TableHandle\", \"list\"’") ) close(data$client) From 45eab4216393c86972a42cee7bfff4f587a55c5e Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Wed, 9 Aug 2023 16:55:21 -0500 Subject: [PATCH 53/73] Update cpp to conform to new styleguide, need to uncomment pct when cpp fixed --- R/rdeephaven/src/client.cpp | 396 ++++++++++++++++++------------------ 1 file changed, 198 insertions(+), 198 deletions(-) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index fc827547742..96010fa7526 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -37,7 +37,7 @@ class AggregateWrapper { public: AggregateWrapper(); AggregateWrapper(deephaven::client::Aggregate aggregate) : - internal_aggregation(std::move(aggregate)) {} + internal_aggregation(std::move(aggregate)) {} private: deephaven::client::Aggregate internal_aggregation; friend TableHandleWrapper; @@ -59,197 +59,197 @@ std::vector convertRcppListToVectorOfTypeAggregate } AggregateWrapper* INTERNAL_agg_min(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::min(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Min(columnSpecs)); } AggregateWrapper* INTERNAL_agg_max(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::max(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Max(columnSpecs)); } AggregateWrapper* INTERNAL_agg_first(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::first(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::First(columnSpecs)); } AggregateWrapper* INTERNAL_agg_last(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::last(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Last(columnSpecs)); } AggregateWrapper* INTERNAL_agg_sum(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::sum(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Sum(columnSpecs)); } AggregateWrapper* INTERNAL_agg_absSum(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::absSum(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::AbsSum(columnSpecs)); } AggregateWrapper* INTERNAL_agg_avg(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::avg(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Avg(columnSpecs)); } AggregateWrapper* INTERNAL_agg_wAvg(std::string weightColumn, std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::wavg(weightColumn, columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::WAvg(weightColumn, columnSpecs)); } AggregateWrapper* INTERNAL_agg_median(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::med(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Med(columnSpecs)); } AggregateWrapper* INTERNAL_agg_var(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::var(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Var(columnSpecs)); } AggregateWrapper* INTERNAL_agg_std(std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::std(columnSpecs)); + return new AggregateWrapper(deephaven::client::Aggregate::Std(columnSpecs)); } -AggregateWrapper* INTERNAL_agg_percentile(double percentile, std::vector columnSpecs) { - return new AggregateWrapper(deephaven::client::Aggregate::pct(percentile, false, columnSpecs)); -} +//AggregateWrapper* INTERNAL_agg_percentile(double percentile, std::vector columnSpecs) { +// return new AggregateWrapper(deephaven::client::Aggregate::Pct(percentile, false, columnSpecs)); +//} AggregateWrapper* INTERNAL_agg_count(std::string columnSpec) { - return new AggregateWrapper(deephaven::client::Aggregate::count(columnSpec)); + return new AggregateWrapper(deephaven::client::Aggregate::Count(columnSpec)); } class TableHandleWrapper { public: TableHandleWrapper(deephaven::client::TableHandle ref_table) : - internal_tbl_hdl(std::move(ref_table)) {}; + internal_tbl_hdl(std::move(ref_table)) {}; - TableHandleWrapper* select(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.select(columnSpecs)); + TableHandleWrapper* Select(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.Select(columnSpecs)); }; - TableHandleWrapper* view(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.view(columnSpecs)); + TableHandleWrapper* View(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.View(columnSpecs)); }; - TableHandleWrapper* update(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.update(columnSpecs)); + TableHandleWrapper* Update(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.Update(columnSpecs)); }; - TableHandleWrapper* updateView(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.updateView(columnSpecs)); + TableHandleWrapper* UpdateView(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.UpdateView(columnSpecs)); }; - TableHandleWrapper* dropColumns(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.dropColumns(columnSpecs)); + TableHandleWrapper* DropColumns(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.DropColumns(columnSpecs)); }; - TableHandleWrapper* where(std::string condition) { - return new TableHandleWrapper(internal_tbl_hdl.where(condition)); + TableHandleWrapper* Where(std::string condition) { + return new TableHandleWrapper(internal_tbl_hdl.Where(condition)); }; - TableHandleWrapper* groupBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.by(columnSpecs)); + TableHandleWrapper* GroupBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.By(columnSpecs)); }; - TableHandleWrapper* ungroup(std::vector groupByColumns) { - return new TableHandleWrapper(internal_tbl_hdl.ungroup(false, groupByColumns)); + TableHandleWrapper* Ungroup(std::vector groupByColumns) { + return new TableHandleWrapper(internal_tbl_hdl.Ungroup(false, groupByColumns)); }; - TableHandleWrapper* aggBy(Rcpp::List aggregations, std::vector groupByColumns) { + TableHandleWrapper* AggBy(Rcpp::List aggregations, std::vector groupByColumns) { std::vector converted_aggregations = convertRcppListToVectorOfTypeAggregate(aggregations); - return new TableHandleWrapper(internal_tbl_hdl.by(deephaven::client::AggregateCombo::create(converted_aggregations), groupByColumns)); + return new TableHandleWrapper(internal_tbl_hdl.By(deephaven::client::AggregateCombo::Create(converted_aggregations), groupByColumns)); } - TableHandleWrapper* firstBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.firstBy(columnSpecs)); + TableHandleWrapper* FirstBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.FirstBy(columnSpecs)); }; - TableHandleWrapper* lastBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.lastBy(columnSpecs)); + TableHandleWrapper* LastBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.LastBy(columnSpecs)); }; - TableHandleWrapper* headBy(int64_t n, std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.headBy(n, columnSpecs)); + TableHandleWrapper* HeadBy(int64_t n, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.HeadBy(n, columnSpecs)); }; - TableHandleWrapper* tailBy(int64_t n, std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.tailBy(n, columnSpecs)); + TableHandleWrapper* TailBy(int64_t n, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.TailBy(n, columnSpecs)); }; - TableHandleWrapper* minBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.minBy(columnSpecs)); + TableHandleWrapper* MinBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.MinBy(columnSpecs)); }; - TableHandleWrapper* maxBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.maxBy(columnSpecs)); + TableHandleWrapper* MaxBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.MaxBy(columnSpecs)); }; - TableHandleWrapper* sumBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.sumBy(columnSpecs)); + TableHandleWrapper* SumBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.SumBy(columnSpecs)); }; - TableHandleWrapper* absSumBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.absSumBy(columnSpecs)); + TableHandleWrapper* AbsSumBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.AbsSumBy(columnSpecs)); }; - TableHandleWrapper* avgBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.avgBy(columnSpecs)); + TableHandleWrapper* AvgBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.AvgBy(columnSpecs)); }; - TableHandleWrapper* wAvgBy(std::string weightColumn, std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.wAvgBy(weightColumn, columnSpecs)); + TableHandleWrapper* WAvgBy(std::string weightColumn, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.WAvgBy(weightColumn, columnSpecs)); }; - TableHandleWrapper* medianBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.medianBy(columnSpecs)); + TableHandleWrapper* MedianBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.MedianBy(columnSpecs)); }; - TableHandleWrapper* varBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.varBy(columnSpecs)); + TableHandleWrapper* VarBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.VarBy(columnSpecs)); }; - TableHandleWrapper* stdBy(std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.stdBy(columnSpecs)); + TableHandleWrapper* StdBy(std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.StdBy(columnSpecs)); }; - TableHandleWrapper* percentileBy(double percentile, std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.percentileBy(percentile, columnSpecs)); + TableHandleWrapper* PercentileBy(double percentile, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.PercentileBy(percentile, columnSpecs)); }; - TableHandleWrapper* countBy(std::string countByColumn, std::vector columnSpecs) { - return new TableHandleWrapper(internal_tbl_hdl.countBy(countByColumn, columnSpecs)); + TableHandleWrapper* CountBy(std::string countByColumn, std::vector columnSpecs) { + return new TableHandleWrapper(internal_tbl_hdl.CountBy(countByColumn, columnSpecs)); }; - TableHandleWrapper* crossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { - return new TableHandleWrapper(internal_tbl_hdl.crossJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + TableHandleWrapper* CrossJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.CrossJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); }; - TableHandleWrapper* naturalJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { - return new TableHandleWrapper(internal_tbl_hdl.naturalJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + TableHandleWrapper* NaturalJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.NaturalJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); }; - TableHandleWrapper* exactJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { - return new TableHandleWrapper(internal_tbl_hdl.exactJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); + TableHandleWrapper* ExactJoin(const TableHandleWrapper &rightSide, std::vector columnsToMatch, std::vector columnsToAdd) { + return new TableHandleWrapper(internal_tbl_hdl.ExactJoin(rightSide.internal_tbl_hdl, columnsToMatch, columnsToAdd)); }; - TableHandleWrapper* head(int64_t n) { - return new TableHandleWrapper(internal_tbl_hdl.head(n)); + TableHandleWrapper* Head(int64_t n) { + return new TableHandleWrapper(internal_tbl_hdl.Head(n)); }; - TableHandleWrapper* tail(int64_t n) { - return new TableHandleWrapper(internal_tbl_hdl.tail(n)); + TableHandleWrapper* Tail(int64_t n) { + return new TableHandleWrapper(internal_tbl_hdl.Tail(n)); }; - TableHandleWrapper* merge(Rcpp::List sources) { + TableHandleWrapper* Merge(Rcpp::List sources) { std::vector converted_sources = convertRcppListToVectorOfTypeTableHandle(sources); - return new TableHandleWrapper(internal_tbl_hdl.merge(converted_sources)); + return new TableHandleWrapper(internal_tbl_hdl.Merge(converted_sources)); }; - TableHandleWrapper* sort(std::vector columnSpecs, std::vector descending) { + TableHandleWrapper* Sort(std::vector columnSpecs, std::vector descending) { std::vector sort_pairs; sort_pairs.reserve(columnSpecs.size()); if (descending.size() == 1) { if (!descending[0]) { for(int i = 0; i < columnSpecs.size(); i++) { - sort_pairs.push_back(deephaven::client::SortPair::ascending(columnSpecs[i], false)); + sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], false)); } } else { for(int i = 0; i < columnSpecs.size(); i++) { - sort_pairs.push_back(deephaven::client::SortPair::descending(columnSpecs[i], false)); + sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], false)); } } } @@ -257,38 +257,38 @@ class TableHandleWrapper { else { for(int i = 0; i < columnSpecs.size(); i++) { if (!descending[i]) { - sort_pairs.push_back(deephaven::client::SortPair::ascending(columnSpecs[i], false)); + sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], false)); } else { - sort_pairs.push_back(deephaven::client::SortPair::descending(columnSpecs[i], false)); + sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], false)); } } } - return new TableHandleWrapper(internal_tbl_hdl.sort(sort_pairs)); + return new TableHandleWrapper(internal_tbl_hdl.Sort(sort_pairs)); }; - bool isStatic() { - return internal_tbl_hdl.isStatic(); + bool IsStatic() { + return internal_tbl_hdl.IsStatic(); } - int64_t numRows() { - return internal_tbl_hdl.numRows(); + int64_t NumRows() { + return internal_tbl_hdl.NumRows(); } - void bindToVariable(std::string tableName) { - internal_tbl_hdl.bindToVariable(tableName); + void BindToVariable(std::string tableName) { + internal_tbl_hdl.BindToVariable(tableName); } /** * Creates and returns a pointer to an ArrowArrayStream C struct containing the data from the table referenced by internal_tbl_hdl. * Intended to be used for creating an Arrow RecordBatchReader in R via RecordBatchReader$import_from_c(ptr). */ - SEXP getArrowArrayStreamPtr() { + SEXP GetArrowArrayStreamPtr() { - std::shared_ptr fsr = internal_tbl_hdl.getFlightStreamReader(); + std::shared_ptr fsr = internal_tbl_hdl.GetFlightStreamReader(); std::vector> empty_record_batches; - deephaven::client::utility::okOrThrow(DEEPHAVEN_EXPR_MSG(fsr->ReadAll(&empty_record_batches))); + deephaven::client::utility::OkOrThrow(DEEPHAVEN_EXPR_MSG(fsr->ReadAll(&empty_record_batches))); std::shared_ptr record_batch_reader = arrow::RecordBatchReader::Make(empty_record_batches).ValueOrDie(); ArrowArrayStream* stream_ptr = new ArrowArrayStream(); @@ -322,42 +322,42 @@ class ClientOptionsWrapper { public: ClientOptionsWrapper() : - internal_options(std::make_shared()) {} + internal_options(std::make_shared()) {} - void setDefaultAuthentication() { - internal_options->setDefaultAuthentication(); + void SetDefaultAuthentication() { + internal_options->SetDefaultAuthentication(); } - void setBasicAuthentication(const std::string &username, const std::string &password) { - internal_options->setBasicAuthentication(username, password); + void SetBasicAuthentication(const std::string &username, const std::string &password) { + internal_options->SetBasicAuthentication(username, password); } - void setCustomAuthentication(const std::string &authenticationKey, const std::string &authenticationValue) { - internal_options->setCustomAuthentication(authenticationKey, authenticationValue); + void SetCustomAuthentication(const std::string &authenticationKey, const std::string &authenticationValue) { + internal_options->SetCustomAuthentication(authenticationKey, authenticationValue); } - void setSessionType(const std::string &sessionType) { - internal_options->setSessionType(sessionType); + void SetSessionType(const std::string &sessionType) { + internal_options->SetSessionType(sessionType); } - void setUseTls(bool useTls) { - internal_options->setUseTls(useTls); + void SetUseTls(bool useTls) { + internal_options->SetUseTls(useTls); } - void setTlsRootCerts(std::string tlsRootCerts) { - internal_options->setTlsRootCerts(tlsRootCerts); + void SetTlsRootCerts(std::string tlsRootCerts) { + internal_options->SetTlsRootCerts(tlsRootCerts); } - void addIntOption(std::string opt, int val) { - internal_options->addIntOption(opt, val); + void AddIntOption(std::string opt, int val) { + internal_options->AddIntOption(opt, val); } - void addStringOption(std::string opt, std::string val) { - internal_options->addStringOption(opt, val); + void AddStringOption(std::string opt, std::string val) { + internal_options->AddStringOption(opt, val); } - void addExtraHeader(std::string header_name, std::string header_value) { - internal_options->addExtraHeader(header_name, header_value); + void AddExtraHeader(std::string header_name, std::string header_value) { + internal_options->AddExtraHeader(header_name, header_value); } private: @@ -370,22 +370,22 @@ class ClientWrapper { public: ClientWrapper(std::string target, const ClientOptionsWrapper &client_options) : - internal_client(deephaven::client::Client::connect(target, *client_options.internal_options)) {} + internal_client(deephaven::client::Client::Connect(target, *client_options.internal_options)) {} - TableHandleWrapper* openTable(std::string tableName) { - return new TableHandleWrapper(internal_tbl_hdl_mngr.fetchTable(tableName)); + TableHandleWrapper* OpenTable(std::string tableName) { + return new TableHandleWrapper(internal_tbl_hdl_mngr.FetchTable(tableName)); } - TableHandleWrapper* emptyTable(int64_t size) { - return new TableHandleWrapper(internal_tbl_hdl_mngr.emptyTable(size)); + TableHandleWrapper* EmptyTable(int64_t size) { + return new TableHandleWrapper(internal_tbl_hdl_mngr.EmptyTable(size)); } - TableHandleWrapper* timeTable(int64_t startTimeNanos, int64_t periodNanos) { - return new TableHandleWrapper(internal_tbl_hdl_mngr.timeTable(startTimeNanos, periodNanos)); + TableHandleWrapper* TimeTable(int64_t startTimeNanos, int64_t periodNanos) { + return new TableHandleWrapper(internal_tbl_hdl_mngr.TimeTable(startTimeNanos, periodNanos)); }; - void runScript(std::string code) { - internal_tbl_hdl_mngr.runScript(code); + void RunScript(std::string code) { + internal_tbl_hdl_mngr.RunScript(code); } /** @@ -393,11 +393,11 @@ class ClientWrapper { * @param tableName Name of the table to search for. * @return Boolean indicating whether tableName exists on the server or not. */ - bool checkForTable(std::string tableName) { + bool CheckForTable(std::string tableName) { // we have to first fetchTable to check existence, fetchTable does not fail on its own, but .observe() will fail if table doesn't exist - deephaven::client::TableHandle table_handle = internal_tbl_hdl_mngr.fetchTable(tableName); + deephaven::client::TableHandle table_handle = internal_tbl_hdl_mngr.FetchTable(tableName); try { - table_handle.observe(); + table_handle.Observe(); } catch(...) { return false; } @@ -408,7 +408,7 @@ class ClientWrapper { * Allocates memory for an ArrowArrayStream C struct and returns a pointer to the new chunk of memory. * Intended to be used to get a pointer to pass to Arrow's R library RecordBatchReader$export_to_c(ptr). */ - SEXP newArrowArrayStreamPtr() { + SEXP NewArrowArrayStreamPtr() { ArrowArrayStream* stream_ptr = new ArrowArrayStream(); return Rcpp::XPtr(stream_ptr, true); } @@ -417,11 +417,11 @@ class ClientWrapper { * Uses a pointer to a populated ArrowArrayStream C struct to create a new table on the server from the data in the C struct. * @param stream_ptr Pointer to an existing and populated ArrayArrayStream, populated by a call to RecordBatchReader$export_to_c(ptr) from R. */ - TableHandleWrapper* newTableFromArrowArrayStreamPtr(Rcpp::XPtr stream_ptr) { + TableHandleWrapper* NewTableFromArrowArrayStreamPtr(Rcpp::XPtr stream_ptr) { - auto wrapper = internal_tbl_hdl_mngr.createFlightWrapper(); + auto wrapper = internal_tbl_hdl_mngr.CreateFlightWrapper(); arrow::flight::FlightCallOptions options; - wrapper.addHeaders(&options); + wrapper.AddHeaders(&options); // extract RecordBatchReader from the struct pointed to by the passed stream_ptr std::shared_ptr record_batch_reader = arrow::ImportRecordBatchReader(stream_ptr.get()).ValueOrDie(); @@ -431,32 +431,32 @@ class ClientWrapper { std::unique_ptr fsw; std::unique_ptr fmr; - auto ticket = internal_tbl_hdl_mngr.newTicket(); - auto fd = deephaven::client::utility::convertTicketToFlightDescriptor(ticket); - - deephaven::client::utility::okOrThrow(DEEPHAVEN_EXPR_MSG(wrapper.flightClient()->DoPut(options, fd, schema, &fsw, &fmr))); + auto ticket = internal_tbl_hdl_mngr.NewTicket(); + auto fd = deephaven::client::utility::ConvertTicketToFlightDescriptor(ticket); + + deephaven::client::utility::OkOrThrow(DEEPHAVEN_EXPR_MSG(wrapper.FlightClient()->DoPut(options, fd, schema, &fsw, &fmr))); while(true) { std::shared_ptr this_batch; - deephaven::client::utility::okOrThrow(DEEPHAVEN_EXPR_MSG(record_batch_reader->ReadNext(&this_batch))); + deephaven::client::utility::OkOrThrow(DEEPHAVEN_EXPR_MSG(record_batch_reader->ReadNext(&this_batch))); if (this_batch == nullptr) { break; } - deephaven::client::utility::okOrThrow(DEEPHAVEN_EXPR_MSG(fsw->WriteRecordBatch(*this_batch))); + deephaven::client::utility::OkOrThrow(DEEPHAVEN_EXPR_MSG(fsw->WriteRecordBatch(*this_batch))); } - deephaven::client::utility::okOrThrow(DEEPHAVEN_EXPR_MSG(fsw->DoneWriting())); - deephaven::client::utility::okOrThrow(DEEPHAVEN_EXPR_MSG(fsw->Close())); + deephaven::client::utility::OkOrThrow(DEEPHAVEN_EXPR_MSG(fsw->DoneWriting())); + deephaven::client::utility::OkOrThrow(DEEPHAVEN_EXPR_MSG(fsw->Close())); - auto new_tbl_hdl = internal_tbl_hdl_mngr.makeTableHandleFromTicket(ticket); + auto new_tbl_hdl = internal_tbl_hdl_mngr.MakeTableHandleFromTicket(ticket); return new TableHandleWrapper(new_tbl_hdl); } - void close() { - internal_client.close(); + void Close() { + internal_client.Close(); } private: deephaven::client::Client internal_client; - const deephaven::client::TableHandleManager internal_tbl_hdl_mngr = internal_client.getManager(); + const deephaven::client::TableHandleManager internal_tbl_hdl_mngr = internal_client.GetManager(); }; @@ -484,78 +484,78 @@ RCPP_MODULE(DeephavenInternalModule) { function("INTERNAL_agg_median", &INTERNAL_agg_median); function("INTERNAL_agg_var", &INTERNAL_agg_var); function("INTERNAL_agg_std", &INTERNAL_agg_std); - function("INTERNAL_agg_percentile", &INTERNAL_agg_percentile); + //function("INTERNAL_agg_percentile", &INTERNAL_agg_percentile); function("INTERNAL_agg_count", &INTERNAL_agg_count); class_("INTERNAL_TableHandle") - .method("select", &TableHandleWrapper::select) - .method("view", &TableHandleWrapper::view) - .method("update", &TableHandleWrapper::update) - .method("update_view", &TableHandleWrapper::updateView) - .method("drop_columns", &TableHandleWrapper::dropColumns) - .method("where", &TableHandleWrapper::where) - - .method("group_by", &TableHandleWrapper::groupBy) - .method("ungroup", &TableHandleWrapper::ungroup) - - .method("agg_by", &TableHandleWrapper::aggBy) - .method("first_by", &TableHandleWrapper::firstBy) - .method("last_by", &TableHandleWrapper::lastBy) - .method("head_by", &TableHandleWrapper::headBy) - .method("tail_by", &TableHandleWrapper::tailBy) - .method("min_by", &TableHandleWrapper::minBy) - .method("max_by", &TableHandleWrapper::maxBy) - .method("sum_by", &TableHandleWrapper::sumBy) - .method("abs_sum_by", &TableHandleWrapper::absSumBy) - .method("avg_by", &TableHandleWrapper::avgBy) - .method("w_avg_by", &TableHandleWrapper::wAvgBy) - .method("median_by", &TableHandleWrapper::medianBy) - .method("var_by", &TableHandleWrapper::varBy) - .method("std_by", &TableHandleWrapper::stdBy) - .method("percentile_by", &TableHandleWrapper::percentileBy) - .method("count_by", &TableHandleWrapper::countBy) - - .method("cross_join", &TableHandleWrapper::crossJoin) - .method("natural_join", &TableHandleWrapper::naturalJoin) - .method("exact_join", &TableHandleWrapper::exactJoin) - - .method("head", &TableHandleWrapper::head) - .method("tail", &TableHandleWrapper::tail) - .method("merge", &TableHandleWrapper::merge) - .method("sort", &TableHandleWrapper::sort) - - .method("is_static", &TableHandleWrapper::isStatic) - .method("num_rows", &TableHandleWrapper::numRows) - .method("bind_to_variable", &TableHandleWrapper::bindToVariable) - .method("get_arrow_array_stream_ptr", &TableHandleWrapper::getArrowArrayStreamPtr) + .method("select", &TableHandleWrapper::Select) + .method("view", &TableHandleWrapper::View) + .method("update", &TableHandleWrapper::Update) + .method("update_view", &TableHandleWrapper::UpdateView) + .method("drop_columns", &TableHandleWrapper::DropColumns) + .method("where", &TableHandleWrapper::Where) + + .method("group_by", &TableHandleWrapper::GroupBy) + .method("ungroup", &TableHandleWrapper::Ungroup) + + .method("agg_by", &TableHandleWrapper::AggBy) + .method("first_by", &TableHandleWrapper::FirstBy) + .method("last_by", &TableHandleWrapper::LastBy) + .method("head_by", &TableHandleWrapper::HeadBy) + .method("tail_by", &TableHandleWrapper::TailBy) + .method("min_by", &TableHandleWrapper::MinBy) + .method("max_by", &TableHandleWrapper::MaxBy) + .method("sum_by", &TableHandleWrapper::SumBy) + .method("abs_sum_by", &TableHandleWrapper::AbsSumBy) + .method("avg_by", &TableHandleWrapper::AvgBy) + .method("w_avg_by", &TableHandleWrapper::WAvgBy) + .method("median_by", &TableHandleWrapper::MedianBy) + .method("var_by", &TableHandleWrapper::VarBy) + .method("std_by", &TableHandleWrapper::StdBy) + .method("percentile_by", &TableHandleWrapper::PercentileBy) + .method("count_by", &TableHandleWrapper::CountBy) + + .method("cross_join", &TableHandleWrapper::CrossJoin) + .method("natural_join", &TableHandleWrapper::NaturalJoin) + .method("exact_join", &TableHandleWrapper::ExactJoin) + + .method("head", &TableHandleWrapper::Head) + .method("tail", &TableHandleWrapper::Tail) + .method("merge", &TableHandleWrapper::Merge) + .method("sort", &TableHandleWrapper::Sort) + + .method("is_static", &TableHandleWrapper::IsStatic) + .method("num_rows", &TableHandleWrapper::NumRows) + .method("bind_to_variable", &TableHandleWrapper::BindToVariable) + .method("get_arrow_array_stream_ptr", &TableHandleWrapper::GetArrowArrayStreamPtr) ; class_("INTERNAL_ClientOptions") .constructor() - .method("set_default_authentication", &ClientOptionsWrapper::setDefaultAuthentication) - .method("set_basic_authentication", &ClientOptionsWrapper::setBasicAuthentication) - .method("set_custom_authentication", &ClientOptionsWrapper::setCustomAuthentication) - .method("set_session_type", &ClientOptionsWrapper::setSessionType) - .method("set_use_tls", &ClientOptionsWrapper::setUseTls) - .method("set_tls_root_certs", &ClientOptionsWrapper::setTlsRootCerts) - .method("add_int_option", &ClientOptionsWrapper::addIntOption) - .method("add_string_option", &ClientOptionsWrapper::addStringOption) - .method("add_extra_header", &ClientOptionsWrapper::addExtraHeader) + .method("set_default_authentication", &ClientOptionsWrapper::SetDefaultAuthentication) + .method("set_basic_authentication", &ClientOptionsWrapper::SetBasicAuthentication) + .method("set_custom_authentication", &ClientOptionsWrapper::SetCustomAuthentication) + .method("set_session_type", &ClientOptionsWrapper::SetSessionType) + .method("set_use_tls", &ClientOptionsWrapper::SetUseTls) + .method("set_tls_root_certs", &ClientOptionsWrapper::SetTlsRootCerts) + .method("add_int_option", &ClientOptionsWrapper::AddIntOption) + .method("add_string_option", &ClientOptionsWrapper::AddStringOption) + .method("add_extra_header", &ClientOptionsWrapper::AddExtraHeader) ; class_("INTERNAL_Client") .constructor() - .method("open_table", &ClientWrapper::openTable) - .method("empty_table", &ClientWrapper::emptyTable) - .method("time_table", &ClientWrapper::timeTable) - .method("check_for_table", &ClientWrapper::checkForTable) - .method("run_script", &ClientWrapper::runScript) - .method("new_arrow_array_stream_ptr", &ClientWrapper::newArrowArrayStreamPtr) - .method("new_table_from_arrow_array_stream_ptr", &ClientWrapper::newTableFromArrowArrayStreamPtr) - .method("close", &ClientWrapper::close) + .method("open_table", &ClientWrapper::OpenTable) + .method("empty_table", &ClientWrapper::EmptyTable) + .method("time_table", &ClientWrapper::TimeTable) + .method("check_for_table", &ClientWrapper::CheckForTable) + .method("run_script", &ClientWrapper::RunScript) + .method("new_arrow_array_stream_ptr", &ClientWrapper::NewArrowArrayStreamPtr) + .method("new_table_from_arrow_array_stream_ptr", &ClientWrapper::NewTableFromArrowArrayStreamPtr) + .method("close", &ClientWrapper::Close) ; -} +} \ No newline at end of file From 7f5ade2bd9a7b85574bc5d62ad99dd9f9f554b72 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 09:30:21 -0500 Subject: [PATCH 54/73] Uncomment pct, all tests pass --- R/rdeephaven/src/client.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 96010fa7526..7f353060132 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -102,9 +102,10 @@ AggregateWrapper* INTERNAL_agg_std(std::vector columnSpecs) { return new AggregateWrapper(deephaven::client::Aggregate::Std(columnSpecs)); } -//AggregateWrapper* INTERNAL_agg_percentile(double percentile, std::vector columnSpecs) { -// return new AggregateWrapper(deephaven::client::Aggregate::Pct(percentile, false, columnSpecs)); -//} +// TODO: capitalize the pct method when a fix is merged +AggregateWrapper* INTERNAL_agg_percentile(double percentile, std::vector columnSpecs) { + return new AggregateWrapper(deephaven::client::Aggregate::pct(percentile, false, columnSpecs)); +} AggregateWrapper* INTERNAL_agg_count(std::string columnSpec) { return new AggregateWrapper(deephaven::client::Aggregate::Count(columnSpec)); @@ -484,7 +485,7 @@ RCPP_MODULE(DeephavenInternalModule) { function("INTERNAL_agg_median", &INTERNAL_agg_median); function("INTERNAL_agg_var", &INTERNAL_agg_var); function("INTERNAL_agg_std", &INTERNAL_agg_std); - //function("INTERNAL_agg_percentile", &INTERNAL_agg_percentile); + function("INTERNAL_agg_percentile", &INTERNAL_agg_percentile); function("INTERNAL_agg_count", &INTERNAL_agg_count); From 37c301d950b2365ae77b25729527d6514e64204b Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 11:54:52 -0500 Subject: [PATCH 55/73] Refactor auth API to conform to Python --- R/rdeephaven/R/client_wrapper.R | 29 +++++++++---------- .../inst/tests/testthat/test_client_wrapper.R | 12 ++++---- R/rdeephaven/src/client.cpp | 11 ++++--- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 58d75230472..67dda9e80c1 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -20,7 +20,7 @@ setMethod( signature = c(target = "character"), function(target, auth_type = "anonymous", - auth_token_pair = "", + auth_token = "", session_type = "python", use_tls = FALSE, tls_root_certs = "", @@ -30,6 +30,10 @@ setMethod( options <- new(INTERNAL_ClientOptions) verify_string("target", target, TRUE) + verify_string("auth_type", auth_type, TRUE) + if (auth_type == "") { + stop("'auth_type' should be a non-empty string.") + } verify_bool("use_tls", use_tls, TRUE) # check if auth_type needs to be changed and set credentials accordingly @@ -37,26 +41,21 @@ setMethod( options$set_default_authentication() } else if (auth_type == "basic") { - if (auth_token_pair != "") { - verify_string("auth_token_pair", auth_token_pair, TRUE) - username_password <- strsplit(auth_token_pair, ":", fixed = TRUE) - options$set_basic_authentication(username_password[1], username_password[2]) + if (auth_token != "") { + verify_string("auth_token", auth_token, TRUE) + options$set_basic_authentication(auth_token) } else { - stop("Basic authentication was requested, but no 'auth_token_pair' was provided.") + stop("Basic authentication was requested, but no 'auth_token' was provided.") } } - else if (auth_type == "custom") { - if (auth_token_pair != "") { - verify_string("auth_token_pair", auth_token_pair, TRUE) - key_value <- strsplit(auth_token_pair, ":", fixed = TRUE) - options$set_custom_authentication(key_value[1], key_value[2]) + else { + if (auth_token != "") { + verify_string("auth_token", auth_token, TRUE) + options$set_custom_authentication(auth_type, auth_token) } else { - stop("Custom authentication was requested, but no 'auth_token_pair' was provided.") + stop("Custom authentication was requested, but no 'auth_token' was provided.") } } - else { - stop(paste0("'auth_type' must be 'anonymous', 'basic', or 'custom', but got ", auth_type, ".")) - } # set session type if a valid session type is provided if ((session_type == "python") || (session_type == "groovy")) { diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index bcde8db7017..c392d94ab76 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -186,19 +186,19 @@ test_that("connect fails nicely with bad inputs", { expect_error( connect(target = "localhost:10000", auth_type = "basic"), - "Basic authentication was requested, but no 'auth_token_pair' was provided." + "Basic authentication was requested, but no 'auth_token' was provided." ) expect_error( connect(target = "localhost:10000", auth_type = "custom"), - "Custom authentication was requested, but no 'auth_token_pair' was provided." + "Custom authentication was requested, but no 'auth_token' was provided." ) expect_error( - connect(target = "localhost:10000", auth_type = "blahblah"), - "'auth_type' must be 'anonymous', 'basic', or 'custom', but got blahblah." + connect(target = "localhost:10000", auth_type = ""), + "'auth_type' should be a non-empty string." ) expect_error( - connect(target = "localhost:10000", auth_type = "basic", auth_token_pair = 1234), - "'auth_token_pair' must be a single string. Got an object of class numeric." + connect(target = "localhost:10000", auth_type = "basic", auth_token = 1234), + "'auth_token' must be a single string. Got an object of class numeric." ) expect_error( connect(target = "localhost:10000", session_type = "blahblah"), diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 7f353060132..d31bcbc27b2 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -20,6 +20,8 @@ #include +using deephaven::dhcore::utility::Base64Encode; + // forward declaration of classes class AggregateWrapper; class TableHandleWrapper; @@ -329,12 +331,13 @@ class ClientOptionsWrapper { internal_options->SetDefaultAuthentication(); } - void SetBasicAuthentication(const std::string &username, const std::string &password) { - internal_options->SetBasicAuthentication(username, password); + void SetBasicAuthentication(const std::string &authentication_token) { + const std::string authentication_token_base64 = Base64Encode(authentication_token); + internal_options->SetCustomAuthentication("Basic", authentication_token_base64); } - void SetCustomAuthentication(const std::string &authenticationKey, const std::string &authenticationValue) { - internal_options->SetCustomAuthentication(authenticationKey, authenticationValue); + void SetCustomAuthentication(const std::string &authentication_type, const std::string &authentication_token) { + internal_options->SetCustomAuthentication(authentication_type, authentication_token); } void SetSessionType(const std::string &sessionType) { From ed616af6dd122451fbf2d8ec0862018bf231f66b Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 12:34:24 -0500 Subject: [PATCH 56/73] Support multiple int/string options and extra headers --- R/rdeephaven/R/client_wrapper.R | 33 ++++++++++--------- R/rdeephaven/R/helper_functions.R | 4 +++ .../inst/tests/testthat/test_client_wrapper.R | 12 +++---- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 67dda9e80c1..f1fd40e1d5c 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -24,9 +24,9 @@ setMethod( session_type = "python", use_tls = FALSE, tls_root_certs = "", - int_option = "", - string_option = "", - extra_header = "") { + int_options = list(), + string_options = list(), + extra_headers = list()) { options <- new(INTERNAL_ClientOptions) verify_string("target", target, TRUE) @@ -75,22 +75,25 @@ setMethod( } # set extra header options if they are provided - if (int_option != "") { - verify_string("int_option", int_option, TRUE) - new_int_option <- strsplit(int_option, ":", fixed = TRUE) - options$add_int_option(new_int_option[1], as.numeric(new_int_option[2])) + if (length(int_options) != 0) { + verify_list("int_options", int_options, TRUE) + for(key in names(int_options)) { + options$add_int_options(key, int_options[[key]]) + } } - if (string_option != "") { - verify_string("string_option", string_option, TRUE) - new_string_option <- strsplit(string_option, ":", fixed = TRUE) - options$add_string_option(new_string_option[1], new_string_option[2]) + if (length(string_options) != 0) { + verify_list("string_options", string_options, TRUE) + for(key in names(string_options)) { + options$add_string_options(key, string_options[[key]]) + } } - if (extra_header != "") { - verify_string("extra_header", extra_header, TRUE) - new_extra_header <- strsplit(extra_header, ":", fixed = TRUE) - options$add_extra_header(new_extra_header[1], new_extra_header[2]) + if (length(extra_headers) != 0) { + verify_list("extra_headers", extra_headers, TRUE) + for(key in names(extra_headers)) { + options$add_extra_headers(key, extra_headers[[key]]) + } } internal_client <- new(INTERNAL_Client, diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 736e7e5b884..8b6fd3d3f3c 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -61,6 +61,10 @@ verify_numeric <- function(arg_name, candidate, is_scalar) { verify_type(arg_name, candidate, "numeric", "numeric", is_scalar) } +verify_list <- function(arg_name, candidate, is_scalar) { + verify_type(arg_name, candidate, "list", "list", is_scalar) +} + verify_in_unit_interval <- function(arg_name, candidate, is_scalar) { verify_numeric(arg_name, candidate, is_scalar) verify_in_range(arg_name, candidate, message = "between 0 and 1 inclusive", lb = 0, ub = 1, lb_open = FALSE, ub_open = FALSE) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index c392d94ab76..c60334a3264 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -213,16 +213,16 @@ test_that("connect fails nicely with bad inputs", { "'use_tls' must be a single boolean. Got an object of class character." ) expect_error( - connect(target = "localhost:10000", int_option = 1234), - "'int_option' must be a single string. Got an object of class numeric." + connect(target = "localhost:10000", int_options = 1234), + "'int_options' must be a single list. Got an object of class numeric." ) expect_error( - connect(target = "localhost:10000", string_option = 1234), - "'string_option' must be a single string. Got an object of class numeric." + connect(target = "localhost:10000", string_options = 1234), + "'string_options' must be a single list. Got an object of class numeric." ) expect_error( - connect(target = "localhost:10000", extra_header = 1234), - "'extra_header' must be a single string. Got an object of class numeric." + connect(target = "localhost:10000", extra_headers = 1234), + "'extra_headers' must be a single list. Got an object of class numeric." ) }) From f7797fb83cdd715e03820a33ad6690bc08ad3714 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 15:32:43 -0500 Subject: [PATCH 57/73] Code review to helper functions --- R/rdeephaven/R/helper_functions.R | 37 ++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 8b6fd3d3f3c..5ea1e6637ba 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -3,26 +3,33 @@ first_class <- function(arg) { } verify_type <- function(arg_name, candidate, required_type, message_type_name, is_scalar) { - - if (is_scalar) { - if (length(candidate) != 1) { - stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got a vector of length ", length(candidate), ".")) - } - } - - if (first_class(candidate) == "list") { + + if (!is_scalar && (first_class(candidate) == "list")) { if (any(lapply(candidate, first_class) != required_type)) { stop(paste0("'", arg_name, "' must be a ", message_type_name, ", or a vector of ", message_type_name, "s. Got a vector with at least one element that is not a ", message_type_name, ".")) } } - else { - if (first_class(candidate) != required_type) { - if (is_scalar) { - stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got an object of class ", first_class(candidate), ".")) - } else { - stop(paste0("'", arg_name, "' must be a ", message_type_name, " or a vector of ", message_type_name, "s. Got an object of class ", first_class(candidate), ".")) - } + + else if (is_scalar && (first_class(candidate) == "list")) { + if (first_class(candidate[[1]]) != required_type) { + stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got an object of class ", first_class(candidate), ".")) } + else if (length(candidate) != 1) { + stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got a vector of length ", length(candidate), ".")) + } + } + + else if (first_class(candidate) != required_type) { + if (!is_scalar) { + stop(paste0("'", arg_name, "' must be a ", message_type_name, " or a vector of ", message_type_name, "s. Got an object of class ", first_class(candidate), ".")) + } + else { + stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got an object of class ", first_class(candidate), ".")) + } + } + + else if (is_scalar && (length(candidate) != 1)) { + stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got a vector of length ", length(candidate), ".")) } } From 8282d38b4dbcbf7cfdb1a7f1b0d2878092675ea7 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 15:41:22 -0500 Subject: [PATCH 58/73] Rename connect to dhConnect --- R/rdeephaven/R/client_wrapper.R | 6 +-- .../inst/tests/testthat/test_agg_by.R | 2 +- .../inst/tests/testthat/test_client_wrapper.R | 54 +++++++++---------- .../testthat/test_table_handle_wrapper.R | 2 +- .../inst/tests/testthat/test_table_ops.R | 2 +- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index f1fd40e1d5c..95d291c5831 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -7,16 +7,16 @@ setClass( ) setGeneric( - "connect", + "dhConnect", function(target, ...) { - return(standardGeneric("connect")) + return(standardGeneric("dhConnect")) }, signature = c("target") ) #' @export setMethod( - "connect", + "dhConnect", signature = c(target = "character"), function(target, auth_type = "anonymous", diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index 259c65d86f2..39302ecf6e9 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -38,7 +38,7 @@ setup <- function() { ) # set up client - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing th1 <- as_dh_table(client, df1) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index c60334a3264..42f91ef9213 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -27,17 +27,17 @@ setup <- function() { ##### TESTING GOOD INPUTS ##### -test_that("client connection works in the simple case of anonymous authentication", { +test_that("client dhConnection works in the simple case of anonymous authentication", { # TODO: assumes server is actually running on localhost:10000, this is probably bad for CI - expect_no_error(client <- connect(target = "localhost:10000")) + expect_no_error(client <- dhConnect(target = "localhost:10000")) }) test_that("as_dh_table does not fail with data frame inputs of simple column types", { data <- setup() - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_no_error(as_dh_table(client, data$df1)) expect_no_error(as_dh_table(client, data$df2)) @@ -50,7 +50,7 @@ test_that("as_dh_table does not fail with data frame inputs of simple column typ test_that("as_dh_table does not fail with tibble inputs of simple column types", { data <- setup() - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_no_error(as_dh_table(client, as_tibble(data$df1))) expect_no_error(as_dh_table(client, as_tibble(data$df2))) @@ -63,7 +63,7 @@ test_that("as_dh_table does not fail with tibble inputs of simple column types", test_that("as_dh_table does not fail with arrow table inputs of simple column types", { data <- setup() - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_no_error(as_dh_table(client, as_arrow_table(data$df1))) expect_no_error(as_dh_table(client, as_arrow_table(data$df2))) @@ -76,7 +76,7 @@ test_that("as_dh_table does not fail with arrow table inputs of simple column ty test_that("as_dh_table does not fail with record batch reader inputs of simple column types", { data <- setup() - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_no_error(as_dh_table(client, as_record_batch_reader(data$df1))) expect_no_error(as_dh_table(client, as_record_batch_reader(data$df2))) @@ -93,7 +93,7 @@ test_that("as_dh_table does not fail with record batch reader inputs of simple c test_that("open_table opens the correct table from the server using %>%", { data <- setup() - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") th1 <- as_dh_table(client, data$df1) th1 %>% bind_to_variable("table1") @@ -117,7 +117,7 @@ test_that("open_table opens the correct table from the server using %>%", { test_that("open_table opens the correct table from the server using |>", { data <- setup() - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") th1 <- as_dh_table(client, data$df1) th1 |> bind_to_variable("table1") @@ -139,7 +139,7 @@ test_that("open_table opens the correct table from the server using |>", { }) test_that("empty_table correctly creates tables on the server using %>%", { - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") th1 <- empty_table(client, 10) %>% update("X = i") df1 <- data.frame(X = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) @@ -149,7 +149,7 @@ test_that("empty_table correctly creates tables on the server using %>%", { }) test_that("empty_table correctly creates tables on the server using |>", { - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") th1 <- empty_table(client, 10) |> update("X = i") df1 <- data.frame(X = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) @@ -161,7 +161,7 @@ test_that("empty_table correctly creates tables on the server using |>", { # TODO: Test time_table good inputs test_that("run_script correctly runs a python script", { - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_no_error(run_script(client, ' @@ -182,46 +182,46 @@ int_col("Name_Int_Col", [44, 55, 66]) ##### TESTING BAD INPUTS ##### -test_that("connect fails nicely with bad inputs", { +test_that("dhConnect fails nicely with bad inputs", { expect_error( - connect(target = "localhost:10000", auth_type = "basic"), + dhConnect(target = "localhost:10000", auth_type = "basic"), "Basic authentication was requested, but no 'auth_token' was provided." ) expect_error( - connect(target = "localhost:10000", auth_type = "custom"), + dhConnect(target = "localhost:10000", auth_type = "custom"), "Custom authentication was requested, but no 'auth_token' was provided." ) expect_error( - connect(target = "localhost:10000", auth_type = ""), + dhConnect(target = "localhost:10000", auth_type = ""), "'auth_type' should be a non-empty string." ) expect_error( - connect(target = "localhost:10000", auth_type = "basic", auth_token = 1234), + dhConnect(target = "localhost:10000", auth_type = "basic", auth_token = 1234), "'auth_token' must be a single string. Got an object of class numeric." ) expect_error( - connect(target = "localhost:10000", session_type = "blahblah"), + dhConnect(target = "localhost:10000", session_type = "blahblah"), "'session_type' must be 'python' or 'groovy', but got blahblah." ) expect_error( - connect(target = "localhost:10000", session_type = 1234), + dhConnect(target = "localhost:10000", session_type = 1234), "'session_type' must be 'python' or 'groovy', but got 1234." ) expect_error( - connect(target = "localhost:10000", use_tls = "banana"), + dhConnect(target = "localhost:10000", use_tls = "banana"), "'use_tls' must be a single boolean. Got an object of class character." ) expect_error( - connect(target = "localhost:10000", int_options = 1234), + dhConnect(target = "localhost:10000", int_options = 1234), "'int_options' must be a single list. Got an object of class numeric." ) expect_error( - connect(target = "localhost:10000", string_options = 1234), + dhConnect(target = "localhost:10000", string_options = 1234), "'string_options' must be a single list. Got an object of class numeric." ) expect_error( - connect(target = "localhost:10000", extra_headers = 1234), + dhConnect(target = "localhost:10000", extra_headers = 1234), "'extra_headers' must be a single list. Got an object of class numeric." ) @@ -230,7 +230,7 @@ test_that("connect fails nicely with bad inputs", { test_that("as_dh_table fails nicely with bad inputs", { library(datasets) - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_error(as_dh_table(client, 12345), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"numeric\"’")) expect_error(as_dh_table(client, "hello!"), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"character\"’")) @@ -246,7 +246,7 @@ test_that("as_dh_table fails nicely with bad inputs", { }) test_that("open_table fails nicely with bad inputs", { - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_error(open_table(client, ""), "The table '' does not exist on the server.") expect_error(open_table(client, 12345), cat("unable to find an inherited method for function ‘open_table’ for signature ‘\"Client\", \"numeric\"’")) @@ -256,7 +256,7 @@ test_that("open_table fails nicely with bad inputs", { }) test_that("empty_table fails nicely with bad inputs", { - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_error(empty_table(client, 0), "'size' must be a positive integer. Got 'size' = 0.") expect_error(empty_table(client, -3), "'size' must be a positive integer. Got 'size' = -3.") @@ -268,7 +268,7 @@ test_that("empty_table fails nicely with bad inputs", { }) test_that("time_table fails nicely with bad inputs", { - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_error(time_table(client, 1.23, 1000), "'period' must be an integer. Got 'period' = 1.23.") expect_error(time_table(client, 1000, 1.23), "'start_time' must be an integer. Got 'start_time' = 1.23.") @@ -281,7 +281,7 @@ test_that("time_table fails nicely with bad inputs", { }) test_that("run_script fails nicely with bad input types", { - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") expect_error(run_script(client, 12345), cat("unable to find an inherited method for function ‘run_script’ for signature ‘\"Client\", \"numeric\"’")) expect_error(run_script(client, c("I", "am", "a", "string")), "'script' must be a single string. Got a vector of length 4.") diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index d7df27382c6..ba46171bd72 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -23,7 +23,7 @@ setup <- function() { ) # set up client - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing th1 <- as_dh_table(client, df1) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 754263e5d7a..e894d98045b 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -38,7 +38,7 @@ setup <- function() { ) # set up client - client <- connect(target = "localhost:10000") + client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing th1 <- as_dh_table(client, df1) From 12149555d28dd4bc32ac2eac3faadd59edf42ec4 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 15:54:49 -0500 Subject: [PATCH 59/73] Update NAMESPACE, add warnings, apply styleguide --- R/rdeephaven/NAMESPACE | 2 +- R/rdeephaven/R/client_wrapper.R | 28 +++++++++++++++++----------- R/rdeephaven/R/helper_functions.R | 19 +++++-------------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index a0c34ddda94..0fdde3a106a 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -27,9 +27,9 @@ exportMethods(as_tibble) exportMethods(avg_by) exportMethods(bind_to_variable) exportMethods(close) -exportMethods(connect) exportMethods(count_by) exportMethods(cross_join) +exportMethods(dhConnect) exportMethods(drop_columns) exportMethods(empty_table) exportMethods(exact_join) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 95d291c5831..59a09c17401 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -28,7 +28,7 @@ setMethod( string_options = list(), extra_headers = list()) { options <- new(INTERNAL_ClientOptions) - + verify_string("target", target, TRUE) verify_string("auth_type", auth_type, TRUE) if (auth_type == "") { @@ -39,16 +39,14 @@ setMethod( # check if auth_type needs to be changed and set credentials accordingly if (auth_type == "anonymous") { options$set_default_authentication() - } - else if (auth_type == "basic") { + } else if (auth_type == "basic") { if (auth_token != "") { verify_string("auth_token", auth_token, TRUE) options$set_basic_authentication(auth_token) } else { stop("Basic authentication was requested, but no 'auth_token' was provided.") } - } - else { + } else { if (auth_token != "") { verify_string("auth_token", auth_token, TRUE) options$set_custom_authentication(auth_type, auth_token) @@ -60,8 +58,7 @@ setMethod( # set session type if a valid session type is provided if ((session_type == "python") || (session_type == "groovy")) { options$set_session_type(session_type) - } - else { + } else { stop(paste0("'session_type' must be 'python' or 'groovy', but got ", session_type, ".")) } @@ -77,25 +74,33 @@ setMethod( # set extra header options if they are provided if (length(int_options) != 0) { verify_list("int_options", int_options, TRUE) - for(key in names(int_options)) { + for (key in names(int_options)) { options$add_int_options(key, int_options[[key]]) } } if (length(string_options) != 0) { verify_list("string_options", string_options, TRUE) - for(key in names(string_options)) { + for (key in names(string_options)) { options$add_string_options(key, string_options[[key]]) } } if (length(extra_headers) != 0) { verify_list("extra_headers", extra_headers, TRUE) - for(key in names(extra_headers)) { + for (key in names(extra_headers)) { options$add_extra_headers(key, extra_headers[[key]]) } } + if ((auth_token != "") && (auth_type == "anonymous")) { + warning("'auth_token' was set but it will not be used, as 'auth_type' is 'anonymous'.") + } + + if ((tls_root_certs != "") && (use_tls == FALSE)) { + warning("'tls_root_certs' was set but it will not be used, as 'use_tls is FALSE.") + } + internal_client <- new(INTERNAL_Client, target = target, client_options = options @@ -187,7 +192,8 @@ setMethod( table_object$export_to_c(ptr) return( new("TableHandle", - .internal_rcpp_object = client_instance@.internal_rcpp_object$new_table_from_arrow_array_stream_ptr(ptr)) + .internal_rcpp_object = client_instance@.internal_rcpp_object$new_table_from_arrow_array_stream_ptr(ptr) + ) ) } ) diff --git a/R/rdeephaven/R/helper_functions.R b/R/rdeephaven/R/helper_functions.R index 5ea1e6637ba..9c2391dbeab 100644 --- a/R/rdeephaven/R/helper_functions.R +++ b/R/rdeephaven/R/helper_functions.R @@ -3,32 +3,23 @@ first_class <- function(arg) { } verify_type <- function(arg_name, candidate, required_type, message_type_name, is_scalar) { - if (!is_scalar && (first_class(candidate) == "list")) { if (any(lapply(candidate, first_class) != required_type)) { stop(paste0("'", arg_name, "' must be a ", message_type_name, ", or a vector of ", message_type_name, "s. Got a vector with at least one element that is not a ", message_type_name, ".")) } - } - - else if (is_scalar && (first_class(candidate) == "list")) { + } else if (is_scalar && (first_class(candidate) == "list")) { if (first_class(candidate[[1]]) != required_type) { stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got an object of class ", first_class(candidate), ".")) - } - else if (length(candidate) != 1) { + } else if (length(candidate) != 1) { stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got a vector of length ", length(candidate), ".")) } - } - - else if (first_class(candidate) != required_type) { + } else if (first_class(candidate) != required_type) { if (!is_scalar) { stop(paste0("'", arg_name, "' must be a ", message_type_name, " or a vector of ", message_type_name, "s. Got an object of class ", first_class(candidate), ".")) - } - else { + } else { stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got an object of class ", first_class(candidate), ".")) } - } - - else if (is_scalar && (length(candidate) != 1)) { + } else if (is_scalar && (length(candidate) != 1)) { stop(paste0("'", arg_name, "' must be a single ", message_type_name, ". Got a vector of length ", length(candidate), ".")) } } From 14a9b115d6df2042f90cd3b2bc81c267c744cbf1 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 15:59:52 -0500 Subject: [PATCH 60/73] Enable size 0 empty_table --- R/rdeephaven/R/client_wrapper.R | 2 +- R/rdeephaven/inst/tests/testthat/test_client_wrapper.R | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 59a09c17401..9357fc76fec 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -151,7 +151,7 @@ setMethod( "empty_table", signature = c(client_instance = "Client", size = "numeric"), function(client_instance, size) { - verify_positive_int("size", size, TRUE) + verify_nonnegative_int("size", size, TRUE) return(new("TableHandle", .internal_rcpp_object = client_instance@.internal_rcpp_object$empty_table(size))) } ) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 42f91ef9213..090315eab33 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -258,7 +258,6 @@ test_that("open_table fails nicely with bad inputs", { test_that("empty_table fails nicely with bad inputs", { client <- dhConnect(target = "localhost:10000") - expect_error(empty_table(client, 0), "'size' must be a positive integer. Got 'size' = 0.") expect_error(empty_table(client, -3), "'size' must be a positive integer. Got 'size' = -3.") expect_error(empty_table(client, 1.2345), "'size' must be an integer. Got 'size' = 1.2345.") expect_error(empty_table(client, "hello!"), cat("unable to find an inherited method for function ‘empty_table’ for signature ‘\"Client\", \"character\"’")) From 9aa73fe2c3105f6fddf4dfc7c6981de4be7dc1c0 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Fri, 11 Aug 2023 17:17:45 -0500 Subject: [PATCH 61/73] Assert options inputs --- R/rdeephaven/R/client_wrapper.R | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 9357fc76fec..d08f6a5b8d3 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -75,6 +75,8 @@ setMethod( if (length(int_options) != 0) { verify_list("int_options", int_options, TRUE) for (key in names(int_options)) { + verify_string("key", key, TRUE) + verify_int("value", int_options[[key]], TRUE) options$add_int_options(key, int_options[[key]]) } } @@ -82,6 +84,8 @@ setMethod( if (length(string_options) != 0) { verify_list("string_options", string_options, TRUE) for (key in names(string_options)) { + verify_string("key", key, TRUE) + verify_string("value", string_options[[key]], TRUE) options$add_string_options(key, string_options[[key]]) } } @@ -89,6 +93,8 @@ setMethod( if (length(extra_headers) != 0) { verify_list("extra_headers", extra_headers, TRUE) for (key in names(extra_headers)) { + verify_string("key", key, TRUE) + verify_string("value", extra_headers[[key]], TRUE) options$add_extra_headers(key, extra_headers[[key]]) } } From 45bbe5df631a97df0944901478b0055d7f1242f3 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Mon, 14 Aug 2023 14:57:07 +0000 Subject: [PATCH 62/73] Starting client_wrapper docs --- R/rdeephaven/R/client_wrapper.R | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index d08f6a5b8d3..f60859cc746 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -1,3 +1,91 @@ +#' @title The Deephaven Client +#' @description The Deephaven Client class is responsible for establishing and maintaining +#' a connection to a running Deephaven server and facilitating basic server requests. +#' @usage NULL +#' @format NULL +#' @docType class +#' @md +#' +#' @section Establishing a server connection with `connect`: +#' Connections to the Deephaven server are established with a call to `connect`, +#' which returns a `Client` object responsible for maintaining the connection and +#' providing an interface to basic server requests. +#' * `x`: an R vector, list, or `data.frame` +#' * `type`: an optional [data type][data-type] for `x`. If omitted, the type +#' will be inferred from the data. +#' +#' `Array$create()` will return the appropriate subclass of `Array`, such as +#' `DictionaryArray` when given an R factor. +#' +#' To compose a `DictionaryArray` directly, call `DictionaryArray$create()`, +#' which takes two arguments: +#' * `x`: an R vector or `Array` of integers for the dictionary indices +#' * `dict`: an R vector or `Array` of dictionary values (like R factor levels +#' but not limited to strings only) +#' @section Usage: +#' +#' ``` +#' a <- Array$create(x) +#' length(a) +#' +#' print(a) +#' a == a +#' ``` +#' +#' @section Methods: +#' +#' - `$IsNull(i)`: Return true if value at index is null. Does not boundscheck +#' - `$IsValid(i)`: Return true if value at index is valid. Does not boundscheck +#' - `$length()`: Size in the number of elements this array contains +#' - `$nbytes()`: Total number of bytes consumed by the elements of the array +#' - `$offset`: A relative position into another array's data, to enable zero-copy slicing +#' - `$null_count`: The number of null entries in the array +#' - `$type`: logical type of data +#' - `$type_id()`: type id +#' - `$Equals(other)` : is this array equal to `other` +#' - `$ApproxEquals(other)` : +#' - `$Diff(other)` : return a string expressing the difference between two arrays +#' - `$data()`: return the underlying [ArrayData][ArrayData] +#' - `$as_vector()`: convert to an R vector +#' - `$ToString()`: string representation of the array +#' - `$Slice(offset, length = NULL)`: Construct a zero-copy slice of the array +#' with the indicated offset and length. If length is `NULL`, the slice goes +#' until the end of the array. +#' - `$Take(i)`: return an `Array` with values at positions given by integers +#' (R vector or Array Array) `i`. +#' - `$Filter(i, keep_na = TRUE)`: return an `Array` with values at positions where logical +#' vector (or Arrow boolean Array) `i` is `TRUE`. +#' - `$SortIndices(descending = FALSE)`: return an `Array` of integer positions that can be +#' used to rearrange the `Array` in ascending or descending order +#' - `$RangeEquals(other, start_idx, end_idx, other_start_idx)` : +#' - `$cast(target_type, safe = TRUE, options = cast_options(safe))`: Alter the +#' data in the array to change its type. +#' - `$View(type)`: Construct a zero-copy view of this array with the given type. +#' - `$Validate()` : Perform any validation checks to determine obvious inconsistencies +#' within the array's internal data. This can be an expensive check, potentially `O(length)` +#' +#' @rdname array-class +#' @examples +#' my_array <- Array$create(1:10) +#' my_array$type +#' my_array$cast(int8()) +#' +#' # Check if value is null; zero-indexed +#' na_array <- Array$create(c(1:5, NA)) +#' na_array$IsNull(0) +#' na_array$IsNull(5) +#' na_array$IsValid(5) +#' na_array$null_count +#' +#' # zero-copy slicing; the offset of the new Array will be the same as the index passed to $Slice +#' new_array <- na_array$Slice(5) +#' new_array$offset +#' +#' # Compare 2 arrays +#' na_array2 <- na_array +#' na_array2 == na_array # element-wise comparison +#' na_array2$Equals(na_array) # overall comparison + #' @export setClass( "Client", From 38b349628e2af143ea8a04a472d2cf5e96ee923a Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 14 Aug 2023 10:06:48 -0500 Subject: [PATCH 63/73] Support ncol() and dim() --- R/rdeephaven/R/table_handle_wrapper.R | 19 +++++++++++++++- .../testthat/test_table_handle_wrapper.R | 22 +++++++++++++++++++ R/rdeephaven/src/client.cpp | 5 +++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index b4ddd46d5e8..1e2cf795618 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -54,7 +54,24 @@ setMethod( } ) -# TODO: Implement ncol, dim +#' @export +setMethod( + "ncol", + signature = c(x = "TableHandle"), + function(x) { + return(x@.internal_rcpp_object$num_cols()) + } +) + +#' @export +setMethod( + "dim", + signature = c(x = "TableHandle"), + function(x) { + return(c(x@.internal_rcpp_object$num_rows(), x@.internal_rcpp_object$num_cols())) + } +) + ### TABLEHANDLE CONVERSIONS ### diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index ba46171bd72..2ea07b0cf4a 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -66,6 +66,28 @@ test_that("nrow returns the correct number of rows", { close(data$client) }) +test_that("ncol returns the correct number of columns", { + data <- setup() + + expect_equal(ncol(data$th1), ncol(data$df1)) + expect_equal(ncol(data$th2), ncol(data$df2)) + expect_equal(ncol(data$th3), ncol(data$df3)) + expect_equal(ncol(data$th4), ncol(data$df4)) + + close(data$client) +}) + +test_that("dim returns the correct dimension", { + data <- setup() + + expect_equal(dim(data$th1), dim(data$df1)) + expect_equal(dim(data$th2), dim(data$df2)) + expect_equal(dim(data$th3), dim(data$df3)) + expect_equal(dim(data$th4), dim(data$df4)) + + close(data$client) +}) + test_that("bind_to_variable binds the table to a variable", { data <- setup() diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index d31bcbc27b2..25e68ef5163 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -278,6 +278,10 @@ class TableHandleWrapper { return internal_tbl_hdl.NumRows(); } + int64_t NumCols() { + return internal_tbl_hdl.Schema()->NumCols(); + } + void BindToVariable(std::string tableName) { internal_tbl_hdl.BindToVariable(tableName); } @@ -531,6 +535,7 @@ RCPP_MODULE(DeephavenInternalModule) { .method("is_static", &TableHandleWrapper::IsStatic) .method("num_rows", &TableHandleWrapper::NumRows) + .method("num_cols", &TableHandleWrapper::NumCols) .method("bind_to_variable", &TableHandleWrapper::BindToVariable) .method("get_arrow_array_stream_ptr", &TableHandleWrapper::GetArrowArrayStreamPtr) ; From 1a0df88f275ecd3e034a67b21797d2c2efe494e6 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 14 Aug 2023 11:51:12 -0500 Subject: [PATCH 64/73] Get rid of mistakenly committed docs, add list type verification in merge --- R/rdeephaven/R/client_wrapper.R | 88 --------------------------------- R/rdeephaven/R/table_ops.R | 1 + 2 files changed, 1 insertion(+), 88 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index f60859cc746..d08f6a5b8d3 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -1,91 +1,3 @@ -#' @title The Deephaven Client -#' @description The Deephaven Client class is responsible for establishing and maintaining -#' a connection to a running Deephaven server and facilitating basic server requests. -#' @usage NULL -#' @format NULL -#' @docType class -#' @md -#' -#' @section Establishing a server connection with `connect`: -#' Connections to the Deephaven server are established with a call to `connect`, -#' which returns a `Client` object responsible for maintaining the connection and -#' providing an interface to basic server requests. -#' * `x`: an R vector, list, or `data.frame` -#' * `type`: an optional [data type][data-type] for `x`. If omitted, the type -#' will be inferred from the data. -#' -#' `Array$create()` will return the appropriate subclass of `Array`, such as -#' `DictionaryArray` when given an R factor. -#' -#' To compose a `DictionaryArray` directly, call `DictionaryArray$create()`, -#' which takes two arguments: -#' * `x`: an R vector or `Array` of integers for the dictionary indices -#' * `dict`: an R vector or `Array` of dictionary values (like R factor levels -#' but not limited to strings only) -#' @section Usage: -#' -#' ``` -#' a <- Array$create(x) -#' length(a) -#' -#' print(a) -#' a == a -#' ``` -#' -#' @section Methods: -#' -#' - `$IsNull(i)`: Return true if value at index is null. Does not boundscheck -#' - `$IsValid(i)`: Return true if value at index is valid. Does not boundscheck -#' - `$length()`: Size in the number of elements this array contains -#' - `$nbytes()`: Total number of bytes consumed by the elements of the array -#' - `$offset`: A relative position into another array's data, to enable zero-copy slicing -#' - `$null_count`: The number of null entries in the array -#' - `$type`: logical type of data -#' - `$type_id()`: type id -#' - `$Equals(other)` : is this array equal to `other` -#' - `$ApproxEquals(other)` : -#' - `$Diff(other)` : return a string expressing the difference between two arrays -#' - `$data()`: return the underlying [ArrayData][ArrayData] -#' - `$as_vector()`: convert to an R vector -#' - `$ToString()`: string representation of the array -#' - `$Slice(offset, length = NULL)`: Construct a zero-copy slice of the array -#' with the indicated offset and length. If length is `NULL`, the slice goes -#' until the end of the array. -#' - `$Take(i)`: return an `Array` with values at positions given by integers -#' (R vector or Array Array) `i`. -#' - `$Filter(i, keep_na = TRUE)`: return an `Array` with values at positions where logical -#' vector (or Arrow boolean Array) `i` is `TRUE`. -#' - `$SortIndices(descending = FALSE)`: return an `Array` of integer positions that can be -#' used to rearrange the `Array` in ascending or descending order -#' - `$RangeEquals(other, start_idx, end_idx, other_start_idx)` : -#' - `$cast(target_type, safe = TRUE, options = cast_options(safe))`: Alter the -#' data in the array to change its type. -#' - `$View(type)`: Construct a zero-copy view of this array with the given type. -#' - `$Validate()` : Perform any validation checks to determine obvious inconsistencies -#' within the array's internal data. This can be an expensive check, potentially `O(length)` -#' -#' @rdname array-class -#' @examples -#' my_array <- Array$create(1:10) -#' my_array$type -#' my_array$cast(int8()) -#' -#' # Check if value is null; zero-indexed -#' na_array <- Array$create(c(1:5, NA)) -#' na_array$IsNull(0) -#' na_array$IsNull(5) -#' na_array$IsValid(5) -#' na_array$null_count -#' -#' # zero-copy slicing; the offset of the new Array will be the same as the index passed to $Slice -#' new_array <- na_array$Slice(5) -#' new_array$offset -#' -#' # Compare 2 arrays -#' na_array2 <- na_array -#' na_array2 == na_array # element-wise comparison -#' na_array2$Equals(na_array) # overall comparison - #' @export setClass( "Client", diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 81aef84de91..0e7a50df87d 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -30,6 +30,7 @@ setMethod( "merge", signature = c(x = "list"), function(x, y = NULL, ...) { + verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) return(base_merge(x, y, c(...))) } ) From ded65240b21fdbaca295c5e180aca41d148ea145 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 14 Aug 2023 12:26:36 -0500 Subject: [PATCH 65/73] Code review suggestions --- R/rdeephaven/NAMESPACE | 4 ++ R/rdeephaven/R/exports.R | 2 +- R/rdeephaven/R/table_handle_wrapper.R | 39 +++++++++++-------- .../inst/tests/testthat/test_client_wrapper.R | 2 +- .../testthat/test_table_handle_wrapper.R | 26 +++++++++++-- .../inst/tests/testthat/test_table_ops.R | 6 +++ 6 files changed, 57 insertions(+), 22 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 0fdde3a106a..e6d0681508c 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -21,6 +21,7 @@ exportMethods(abs_sum_by) exportMethods(agg_by) exportMethods(as.data.frame) exportMethods(as_arrow_table) +exportMethods(as_data_frame) exportMethods(as_dh_table) exportMethods(as_record_batch_reader) exportMethods(as_tibble) @@ -30,6 +31,7 @@ exportMethods(close) exportMethods(count_by) exportMethods(cross_join) exportMethods(dhConnect) +exportMethods(dim) exportMethods(drop_columns) exportMethods(empty_table) exportMethods(exact_join) @@ -44,6 +46,7 @@ exportMethods(median_by) exportMethods(merge) exportMethods(min_by) exportMethods(natural_join) +exportMethods(ncol) exportMethods(nrow) exportMethods(open_table) exportMethods(percentile_by) @@ -70,6 +73,7 @@ importFrom(arrow,Table) importFrom(arrow,arrow_table) importFrom(arrow,as_arrow_table) importFrom(arrow,as_record_batch_reader) +importFrom(dplyr,as_data_frame) importFrom(dplyr,as_tibble) importFrom(magrittr,"%>%") useDynLib(rdeephaven, .registration = TRUE) diff --git a/R/rdeephaven/R/exports.R b/R/rdeephaven/R/exports.R index 5809ae84b61..e786e262108 100644 --- a/R/rdeephaven/R/exports.R +++ b/R/rdeephaven/R/exports.R @@ -4,6 +4,6 @@ #' #' @importFrom magrittr %>% #' @importFrom arrow arrow_table as_arrow_table as_record_batch_reader Table RecordBatchReader RecordBatchStreamReader -#' @importFrom dplyr as_tibble +#' @importFrom dplyr as_tibble as_data_frame loadModule("DeephavenInternalModule", TRUE) diff --git a/R/rdeephaven/R/table_handle_wrapper.R b/R/rdeephaven/R/table_handle_wrapper.R index 1e2cf795618..349b8aba7cb 100644 --- a/R/rdeephaven/R/table_handle_wrapper.R +++ b/R/rdeephaven/R/table_handle_wrapper.R @@ -72,6 +72,25 @@ setMethod( } ) +setGeneric( + "bind_to_variable", + function(table_handle_instance, name) { + return(standardGeneric("bind_to_variable")) + }, + signature = c("table_handle_instance", "name") +) + +#' @export +setMethod( + "bind_to_variable", + signature = c(table_handle_instance = "TableHandle", name = "character"), + function(table_handle_instance, name) { + verify_string("name", name, TRUE) + table_handle_instance@.internal_rcpp_object$bind_to_variable(name) + return(NULL) + } +) + ### TABLEHANDLE CONVERSIONS ### @@ -118,23 +137,11 @@ setMethod( } ) -### TABLEHANDLE OPERATIONS ### - -setGeneric( - "bind_to_variable", - function(table_handle_instance, name) { - return(standardGeneric("bind_to_variable")) - }, - signature = c("table_handle_instance", "name") -) - #' @export setMethod( - "bind_to_variable", - signature = c(table_handle_instance = "TableHandle", name = "character"), - function(table_handle_instance, name) { - verify_string("name", name, TRUE) - table_handle_instance@.internal_rcpp_object$bind_to_variable(name) - return(NULL) + "as_data_frame", + signature = c(x = "TableHandle"), + function(x, ...) { + return(as.data.frame(x)) } ) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 090315eab33..0a9c483aafb 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -258,7 +258,7 @@ test_that("open_table fails nicely with bad inputs", { test_that("empty_table fails nicely with bad inputs", { client <- dhConnect(target = "localhost:10000") - expect_error(empty_table(client, -3), "'size' must be a positive integer. Got 'size' = -3.") + expect_error(empty_table(client, -3), "'size' must be a nonnegative integer. Got 'size' = -3.") expect_error(empty_table(client, 1.2345), "'size' must be an integer. Got 'size' = 1.2345.") expect_error(empty_table(client, "hello!"), cat("unable to find an inherited method for function ‘empty_table’ for signature ‘\"Client\", \"character\"’")) expect_error(empty_table(client, c(1, 2, 3, 4)), "'size' must be a single numeric. Got a vector of length 4.") diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 2ea07b0cf4a..4091bc6547d 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -106,7 +106,7 @@ test_that("bind_to_variable binds the table to a variable", { close(data$client) }) -test_that("to_record_batch_reader returns an identical stream reader", { +test_that("as_record_batch_reader returns an identical stream reader", { data <- setup() # actual equality of RecordBatchStreamReaders is not expected, as they contain underlying pointers to relevant data, @@ -129,7 +129,7 @@ test_that("to_record_batch_reader returns an identical stream reader", { close(data$client) }) -test_that("to_arrow_table returns a valid Arrow table", { +test_that("as_arrow_table returns the correct Arrow table", { data <- setup() # The rationale for casting RecordBatchStreamReaders to dataframes for comparison also applies to Arrow Tables. @@ -150,7 +150,7 @@ test_that("to_arrow_table returns a valid Arrow table", { close(data$client) }) -test_that("to_tibble returns a valid Tibble", { +test_that("as_tibble returns the correct Tibble", { data <- setup() tibble1 <- as_tibble(data$th1) @@ -168,7 +168,7 @@ test_that("to_tibble returns a valid Tibble", { close(data$client) }) -test_that("to_data_frame returns a valid data frame", { +test_that("as.data.frame returns the correct data frame", { data <- setup() data_frame1 <- as.data.frame(data$th1) @@ -186,6 +186,24 @@ test_that("to_data_frame returns a valid data frame", { close(data$client) }) +test_that("as_data_frame returns the correct data frame", { + data <- setup() + + data_frame1 <- as_data_frame(data$th1) + expect_equal(data_frame1, data$df1) + + data_frame2 <- as_data_frame(data$th2) + expect_equal(data_frame2, data$df2) + + data_frame3 <- as_data_frame(data$th3) + expect_equal(data_frame3, data$df3) + + data_frame4 <- as_data_frame(data$th4) + expect_equal(data_frame4, data$df4) + + close(data$client) +}) + ##### TESTING BAD INPUTS ##### test_that("bind_to_variable fails nicely on bad inputs", { diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index e894d98045b..b1baa43fb8f 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -99,6 +99,12 @@ test_that("merge behaves as expected", { new_th12 <- merge(c(data$th5, data$th6, data$th6, data$th5)) expect_equal(as.data.frame(new_th12), new_df3) + new_th13 <- merge(data$th5, c(data$th6, NULL)) + expect_equal(as.data.frame(new_th13), new_df2) + + new_th14 <- merge(c(NULL, data$th5), data$th6) + expect_equal(as.data.frame(new_th14), new_df2) + }) test_that("select behaves as expected", { From a7ea30d56312d22ff8bb59d0141f193d55f4ca19 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 14 Aug 2023 12:46:02 -0500 Subject: [PATCH 66/73] Verified that exact_join is an analog of left_join --- R/rdeephaven/inst/tests/testthat/test_table_ops.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index b1baa43fb8f..5ee60b17ce9 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -859,7 +859,6 @@ test_that("natural_join behaves as expected", { close(data$client) }) -# TODO: Verify that inner_join is the analog of exact_join test_that("exact_join behaves as expected", { data <- setup() @@ -877,7 +876,7 @@ test_that("exact_join behaves as expected", { dplyr::group_by(X) %>% summarise(across(everything(), mean)) new_tb1 <- data$df5 %>% - inner_join(new_tb2, by = "X") %>% + left_join(new_tb2, by = "X") %>% rename(Number1 = Number1.x, Number2 = Number2.x, Number3 = Number1.y, Number4 = Number2.y) expect_equal(as.data.frame(new_th1), as.data.frame(new_tb1)) From 7b0cfb38dc288910cd1df986a295861d9ca05ae2 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 14 Aug 2023 16:10:53 -0500 Subject: [PATCH 67/73] Expand sort API, constrain merge args, add username and password to dhConnect --- R/rdeephaven/R/client_wrapper.R | 15 +- R/rdeephaven/R/table_ops.R | 172 ++++++++++-------- .../inst/tests/testthat/test_client_wrapper.R | 4 +- .../inst/tests/testthat/test_table_ops.R | 36 +--- R/rdeephaven/src/client.cpp | 33 ++-- 5 files changed, 125 insertions(+), 135 deletions(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index d08f6a5b8d3..4cad8bb6ae3 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -20,6 +20,8 @@ setMethod( signature = c(target = "character"), function(target, auth_type = "anonymous", + username = "", + password = "", auth_token = "", session_type = "python", use_tls = FALSE, @@ -40,11 +42,12 @@ setMethod( if (auth_type == "anonymous") { options$set_default_authentication() } else if (auth_type == "basic") { - if (auth_token != "") { - verify_string("auth_token", auth_token, TRUE) - options$set_basic_authentication(auth_token) + if ((username != "") && (password != "")) { + verify_string("username", username, TRUE) + verify_string("password", password, TRUE) + options$set_basic_authentication(username, password) } else { - stop("Basic authentication was requested, but no 'auth_token' was provided.") + stop("Basic authentication was requested, but at least one of 'username' or 'password' was not provided.") } } else { if (auth_token != "") { @@ -102,6 +105,10 @@ setMethod( if ((auth_token != "") && (auth_type == "anonymous")) { warning("'auth_token' was set but it will not be used, as 'auth_type' is 'anonymous'.") } + + if (((username != "") || (password != "")) && auth_type != "basic") { + warning("At least one of 'username' and 'password' were set but they will not be used, as 'auth_type' is not 'basic'.") + } if ((tls_root_certs != "") && (use_tls == FALSE)) { warning("'tls_root_certs' was set but it will not be used, as 'use_tls is FALSE.") diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 0e7a50df87d..84ba570dbd6 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -19,39 +19,19 @@ base_merge <- function(x, y, ...) { #' @export setMethod( "merge", - signature = c(x = "TableHandle"), - function(x, y = NULL, ...) { - return(base_merge(x, y, c(...))) - } -) - -#' @export -setMethod( - "merge", - signature = c(x = "list"), - function(x, y = NULL, ...) { + signature = c(x = "list", y = "missing"), + function(x, y = NULL) { verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y, c(...))) - } -) - -#' @export -setMethod( - "merge", - signature = c(x = "TableHandle", y = "list"), - function(x, y, ...) { - verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y, c(...))) + return(base_merge(x, y)) } ) #' @export setMethod( "merge", - signature = c(x = "list", y = "TableHandle"), - function(x, y, ...) { - verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y, c(...))) + signature = c(x = "TableHandle", y = "missing"), + function(x, y = NULL) { + return(base_merge(x, y)) } ) @@ -60,58 +40,90 @@ setMethod( "merge", signature = c(x = "TableHandle", y = "TableHandle"), function(x, y, ...) { + if (length(c(...)) != 0) { + verify_type("...", c(...), "TableHandle", "Deephaven TableHandle", FALSE) + } return(base_merge(x, y, c(...))) } ) -#' @export -setMethod( - "merge", - signature = c(x = "list", y = "list"), - function(x, y, ...) { - verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) - verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y, c(...))) - } -) - -#' @export -setMethod( - "merge", - signature = c(x = "NULL", y = "TableHandle"), - function(x, y, ...) { - return(base_merge(x, y, c(...))) - } -) - -#' @export -setMethod( - "merge", - signature = c(x = "NULL", y = "list"), - function(x, y, ...) { - verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y, c(...))) - } -) - -#' @export -setMethod( - "merge", - signature = c(x = "TableHandle", y = "NULL"), - function(x, y, ...) { - return(base_merge(x, y, c(...))) - } -) - -#' @export -setMethod( - "merge", - signature = c(x = "list", y = "NULL"), - function(x, y, ...) { - verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y, c(...))) - } -) +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "TableHandle", y = "list"), +#' function(x, y, ...) { +#' verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) +#' return(base_merge(x, y, c(...))) +#' } +#' ) +#' +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "list", y = "TableHandle"), +#' function(x, y, ...) { +#' verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) +#' return(base_merge(x, y, c(...))) +#' } +#' ) +#' +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "TableHandle", y = "TableHandle"), +#' function(x, y, ...) { +#' return(base_merge(x, y, c(...))) +#' } +#' ) +#' +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "list", y = "list"), +#' function(x, y, ...) { +#' verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) +#' verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) +#' return(base_merge(x, y, c(...))) +#' } +#' ) +#' +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "NULL", y = "TableHandle"), +#' function(x, y, ...) { +#' return(base_merge(x, y, c(...))) +#' } +#' ) +#' +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "NULL", y = "list"), +#' function(x, y, ...) { +#' verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) +#' return(base_merge(x, y, c(...))) +#' } +#' ) +#' +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "TableHandle", y = "NULL"), +#' function(x, y, ...) { +#' return(base_merge(x, y, c(...))) +#' } +#' ) +#' +#' #' @export +#' setMethod( +#' "merge", +#' signature = c(x = "list", y = "NULL"), +#' function(x, y, ...) { +#' verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) +#' return(base_merge(x, y, c(...))) +#' } +#' ) setGeneric( "select", @@ -622,7 +634,7 @@ setMethod( #' @export setGeneric( "sort", - function(table_handle, by = character(), descending = FALSE, ...) { + function(table_handle, by = character(), descending = FALSE, abs_col = FALSE, ...) { standardGeneric("sort") }, signature = c("table_handle", "by", "descending") @@ -632,12 +644,16 @@ setGeneric( setMethod( "sort", signature = c(table_handle = "TableHandle"), - function(table_handle, by, descending = FALSE) { + function(table_handle, by, descending = FALSE, abs_col = FALSE) { verify_string("by", by, FALSE) verify_bool("descending", descending, FALSE) + verify_bool("abs_col", abs_col, FALSE) if ((length(descending) > 1) && length(descending) != length(by)) { - stop(paste0("'descending' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'descending' with length", length(descending), ".")) + stop(paste0("'descending' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'descending' with length ", length(descending), ".")) + } + if ((length(abs_col) > 1) && length(abs_col) != length(by)) { + stop(paste0("'abs_col' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'abs_col' with length ", length(abs_col), ".")) } - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(by, descending))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(by, descending, abs_col))) } ) diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 0a9c483aafb..6207f6209e4 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -186,7 +186,7 @@ test_that("dhConnect fails nicely with bad inputs", { expect_error( dhConnect(target = "localhost:10000", auth_type = "basic"), - "Basic authentication was requested, but no 'auth_token' was provided." + "Basic authentication was requested, but at least one of 'username' or 'password' was not provided." ) expect_error( dhConnect(target = "localhost:10000", auth_type = "custom"), @@ -198,7 +198,7 @@ test_that("dhConnect fails nicely with bad inputs", { ) expect_error( dhConnect(target = "localhost:10000", auth_type = "basic", auth_token = 1234), - "'auth_token' must be a single string. Got an object of class numeric." + "Basic authentication was requested, but at least one of 'username' or 'password' was not provided." ) expect_error( dhConnect(target = "localhost:10000", session_type = "blahblah"), diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 5ee60b17ce9..6e67bd072e4 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -72,39 +72,13 @@ test_that("merge behaves as expected", { new_th3 <- merge(data$th5, data$th6, data$th6, data$th5) expect_equal(as.data.frame(new_th3), new_df3) - new_th4 <- merge(data$th5, NULL) - expect_equal(as.data.frame(new_th4), new_df1) + new_th4 <- merge(c(data$th5, data$th6)) + expect_equal(as.data.frame(new_th4), new_df2) - new_th5 <- merge(NULL, data$th5) - expect_equal(as.data.frame(new_th5), new_df1) - - new_th6 <- merge(c(data$th5, data$th6)) - expect_equal(as.data.frame(new_th6), new_df2) - - new_th7 <- merge(NULL, c(data$th5, data$th6)) - expect_equal(as.data.frame(new_th7), new_df2) - - new_th8 <- merge(c(data$th5, data$th6), NULL) - expect_equal(as.data.frame(new_th8), new_df2) - - new_th9 <- merge(data$th5, c(data$th6, data$th6, data$th5)) - expect_equal(as.data.frame(new_th9), new_df3) - - new_th10 <- merge(c(data$th5, data$th6, data$th6), data$th5) - expect_equal(as.data.frame(new_th10), new_df3) - - new_th11 <- merge(c(data$th5, data$th6), c(data$th6, data$th5)) - expect_equal(as.data.frame(new_th11), new_df3) - - new_th12 <- merge(c(data$th5, data$th6, data$th6, data$th5)) - expect_equal(as.data.frame(new_th12), new_df3) - - new_th13 <- merge(data$th5, c(data$th6, NULL)) - expect_equal(as.data.frame(new_th13), new_df2) - - new_th14 <- merge(c(NULL, data$th5), data$th6) - expect_equal(as.data.frame(new_th14), new_df2) + new_th5 <- merge(c(data$th5, data$th6, NULL, data$th6, data$th5)) + expect_equal(as.data.frame(new_th5), new_df3) + close(data$client) }) test_that("select behaves as expected", { diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 25e68ef5163..13d1f058426 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -241,29 +241,23 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.Merge(converted_sources)); }; - TableHandleWrapper* Sort(std::vector columnSpecs, std::vector descending) { + TableHandleWrapper* Sort(std::vector columnSpecs, std::vector descending, std::vector absCol) { std::vector sort_pairs; sort_pairs.reserve(columnSpecs.size()); if (descending.size() == 1) { - if (!descending[0]) { - for(int i = 0; i < columnSpecs.size(); i++) { - sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], false)); - } - } else { - for(int i = 0; i < columnSpecs.size(); i++) { - sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], false)); - } - } + descending = std::vector(columnSpecs.size(), descending[0]); } - else { - for(int i = 0; i < columnSpecs.size(); i++) { - if (!descending[i]) { - sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], false)); - } else { - sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], false)); - } + if (absCol.size() == 1) { + absCol = std::vector(columnSpecs.size(), absCol[0]); + } + + for(int i = 0; i < columnSpecs.size(); i++) { + if (!descending[i]) { + sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], absCol[i])); + } else { + sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], absCol[i])); } } @@ -335,9 +329,8 @@ class ClientOptionsWrapper { internal_options->SetDefaultAuthentication(); } - void SetBasicAuthentication(const std::string &authentication_token) { - const std::string authentication_token_base64 = Base64Encode(authentication_token); - internal_options->SetCustomAuthentication("Basic", authentication_token_base64); + void SetBasicAuthentication(const std::string &username, const std::string &password) { + internal_options->SetBasicAuthentication(username, password); } void SetCustomAuthentication(const std::string &authentication_type, const std::string &authentication_token) { From d4e7686ade7dc7b75d4e296cc7194f35789c6138 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Mon, 14 Aug 2023 22:43:12 -0500 Subject: [PATCH 68/73] Apply code review --- R/rdeephaven/NAMESPACE | 2 +- R/rdeephaven/R/client_wrapper.R | 30 +++--- R/rdeephaven/R/table_ops.R | 90 +++--------------- .../inst/tests/testthat/test_agg_by.R | 12 +-- .../inst/tests/testthat/test_client_wrapper.R | 92 +++++++++++-------- .../testthat/test_table_handle_wrapper.R | 8 +- .../inst/tests/testthat/test_table_ops.R | 15 +-- R/rdeephaven/src/client.cpp | 15 +-- 8 files changed, 115 insertions(+), 149 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index e6d0681508c..069032db3ed 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -22,7 +22,7 @@ exportMethods(agg_by) exportMethods(as.data.frame) exportMethods(as_arrow_table) exportMethods(as_data_frame) -exportMethods(as_dh_table) +exportMethods(push_to_table) exportMethods(as_record_batch_reader) exportMethods(as_tibble) exportMethods(avg_by) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index 4cad8bb6ae3..aaede75cc93 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -42,12 +42,18 @@ setMethod( if (auth_type == "anonymous") { options$set_default_authentication() } else if (auth_type == "basic") { - if ((username != "") && (password != "")) { + if (((username != "") && (password != "")) && (auth_token == "")) { verify_string("username", username, TRUE) verify_string("password", password, TRUE) - options$set_basic_authentication(username, password) + user_pass_token = paste(username, ":", password, sep = "") + options$set_basic_authentication(user_pass_token) + } else if (((username == "") && (password == "")) && (auth_token != "")) { + verify_string("auth_token", auth_token, TRUE) + options$set_basic_authentication(auth_token) + } else if (((username != "") || (password != "")) && (auth_token != "")) { + stop("Basic authentication was requested, but 'auth_token' was provided, as well as least one of 'username' and 'password'. Please provide either 'username' and 'password', or 'auth_token'.") } else { - stop("Basic authentication was requested, but at least one of 'username' or 'password' was not provided.") + stop("Basic authentication was requested, but 'auth_token' was not provided, and at most one of 'username' or 'password' was provided. Please provide either 'username' and 'password', or 'auth_token'.") } } else { if (auth_token != "") { @@ -189,16 +195,16 @@ setMethod( ) setGeneric( - "as_dh_table", + "push_to_table", function(client_instance, table_object) { - return(standardGeneric("as_dh_table")) + return(standardGeneric("push_to_table")) }, signature = c("client_instance", "table_object") ) #' @export setMethod( - "as_dh_table", + "push_to_table", signature = c(client_instance = "Client", table_object = "RecordBatchReader"), function(client_instance, table_object) { ptr <- client_instance@.internal_rcpp_object$new_arrow_array_stream_ptr() @@ -213,28 +219,28 @@ setMethod( #' @export setMethod( - "as_dh_table", + "push_to_table", signature = c(client_instance = "Client", table_object = "Table"), function(client_instance, table_object) { - return(as_dh_table(client_instance, as_record_batch_reader(table_object))) + return(push_to_table(client_instance, as_record_batch_reader(table_object))) } ) #' @export setMethod( - "as_dh_table", + "push_to_table", signature = c(client_instance = "Client", table_object = "tbl_df"), function(client_instance, table_object) { - return(as_dh_table(client_instance, arrow_table(table_object))) + return(push_to_table(client_instance, arrow_table(table_object))) } ) #' @export setMethod( - "as_dh_table", + "push_to_table", signature = c(client_instance = "Client", table_object = "data.frame"), function(client_instance, table_object) { - return(as_dh_table(client_instance, arrow_table(table_object))) + return(push_to_table(client_instance, arrow_table(table_object))) } ) diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 84ba570dbd6..98f438e4c38 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -16,6 +16,7 @@ base_merge <- function(x, y, ...) { return(new("TableHandle", .internal_rcpp_object = unwrapped_arg_list[[1]]$merge(unwrapped_arg_list[2:length(unwrapped_arg_list)]))) } +# supports merge(c(t1, t2, t3)) #' @export setMethod( "merge", @@ -26,6 +27,7 @@ setMethod( } ) +# supports merge(t1) edge case #' @export setMethod( "merge", @@ -35,6 +37,7 @@ setMethod( } ) +# supports merge(t1, t2, t3) #' @export setMethod( "merge", @@ -47,83 +50,16 @@ setMethod( } ) -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "TableHandle", y = "list"), -#' function(x, y, ...) { -#' verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) -#' return(base_merge(x, y, c(...))) -#' } -#' ) -#' -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "list", y = "TableHandle"), -#' function(x, y, ...) { -#' verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) -#' return(base_merge(x, y, c(...))) -#' } -#' ) -#' -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "TableHandle", y = "TableHandle"), -#' function(x, y, ...) { -#' return(base_merge(x, y, c(...))) -#' } -#' ) -#' -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "list", y = "list"), -#' function(x, y, ...) { -#' verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) -#' verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) -#' return(base_merge(x, y, c(...))) -#' } -#' ) -#' -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "NULL", y = "TableHandle"), -#' function(x, y, ...) { -#' return(base_merge(x, y, c(...))) -#' } -#' ) -#' -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "NULL", y = "list"), -#' function(x, y, ...) { -#' verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) -#' return(base_merge(x, y, c(...))) -#' } -#' ) -#' -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "TableHandle", y = "NULL"), -#' function(x, y, ...) { -#' return(base_merge(x, y, c(...))) -#' } -#' ) -#' -#' #' @export -#' setMethod( -#' "merge", -#' signature = c(x = "list", y = "NULL"), -#' function(x, y, ...) { -#' verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) -#' return(base_merge(x, y, c(...))) -#' } -#' ) +# supports merge(t1, c(t2, t3)) +#' @export +setMethod( + "merge", + signature = c(x = "TableHandle", y = "list"), + function(x, y) { + verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) + return(base_merge(x, y)) + } +) setGeneric( "select", diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index 39302ecf6e9..d14fa6b7cd1 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -41,12 +41,12 @@ setup <- function() { client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- as_dh_table(client, df1) - th2 <- as_dh_table(client, df2) - th3 <- as_dh_table(client, df3) - th4 <- as_dh_table(client, df4) - th5 <- as_dh_table(client, df5) - th6 <- as_dh_table(client, df6) + th1 <- push_to_table(client, df1) + th2 <- push_to_table(client, df2) + th3 <- push_to_table(client, df3) + th4 <- push_to_table(client, df4) + th5 <- push_to_table(client, df5) + th6 <- push_to_table(client, df6) return(list( "client" = client, diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index 6207f6209e4..a3a25b7759a 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -34,59 +34,59 @@ test_that("client dhConnection works in the simple case of anonymous authenticat }) -test_that("as_dh_table does not fail with data frame inputs of simple column types", { +test_that("push_to_table does not fail with data frame inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(as_dh_table(client, data$df1)) - expect_no_error(as_dh_table(client, data$df2)) - expect_no_error(as_dh_table(client, data$df3)) - expect_no_error(as_dh_table(client, data$df4)) + expect_no_error(push_to_table(client, data$df1)) + expect_no_error(push_to_table(client, data$df2)) + expect_no_error(push_to_table(client, data$df3)) + expect_no_error(push_to_table(client, data$df4)) close(client) }) -test_that("as_dh_table does not fail with tibble inputs of simple column types", { +test_that("push_to_table does not fail with tibble inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(as_dh_table(client, as_tibble(data$df1))) - expect_no_error(as_dh_table(client, as_tibble(data$df2))) - expect_no_error(as_dh_table(client, as_tibble(data$df3))) - expect_no_error(as_dh_table(client, as_tibble(data$df4))) + expect_no_error(push_to_table(client, as_tibble(data$df1))) + expect_no_error(push_to_table(client, as_tibble(data$df2))) + expect_no_error(push_to_table(client, as_tibble(data$df3))) + expect_no_error(push_to_table(client, as_tibble(data$df4))) close(client) }) -test_that("as_dh_table does not fail with arrow table inputs of simple column types", { +test_that("push_to_table does not fail with arrow table inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(as_dh_table(client, as_arrow_table(data$df1))) - expect_no_error(as_dh_table(client, as_arrow_table(data$df2))) - expect_no_error(as_dh_table(client, as_arrow_table(data$df3))) - expect_no_error(as_dh_table(client, as_arrow_table(data$df4))) + expect_no_error(push_to_table(client, as_arrow_table(data$df1))) + expect_no_error(push_to_table(client, as_arrow_table(data$df2))) + expect_no_error(push_to_table(client, as_arrow_table(data$df3))) + expect_no_error(push_to_table(client, as_arrow_table(data$df4))) close(client) }) -test_that("as_dh_table does not fail with record batch reader inputs of simple column types", { +test_that("push_to_table does not fail with record batch reader inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(as_dh_table(client, as_record_batch_reader(data$df1))) - expect_no_error(as_dh_table(client, as_record_batch_reader(data$df2))) - expect_no_error(as_dh_table(client, as_record_batch_reader(data$df3))) - expect_no_error(as_dh_table(client, as_record_batch_reader(data$df4))) + expect_no_error(push_to_table(client, as_record_batch_reader(data$df1))) + expect_no_error(push_to_table(client, as_record_batch_reader(data$df2))) + expect_no_error(push_to_table(client, as_record_batch_reader(data$df3))) + expect_no_error(push_to_table(client, as_record_batch_reader(data$df4))) close(client) }) -# The following tests assume the correctness of as_dh_table(...) AND bind_to_variable(), +# The following tests assume the correctness of push_to_table(...) AND bind_to_variable(), # as we have to create data, push it to the server, and name it in order to test open_table(). # Additionally, we assume the correctness of as.data.frame() to make concrete comparisons. @@ -95,19 +95,19 @@ test_that("open_table opens the correct table from the server using %>%", { client <- dhConnect(target = "localhost:10000") - th1 <- as_dh_table(client, data$df1) + th1 <- push_to_table(client, data$df1) th1 %>% bind_to_variable("table1") expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) - th2 <- as_dh_table(client, data$df2) + th2 <- push_to_table(client, data$df2) th2 %>% bind_to_variable("table2") expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) - th3 <- as_dh_table(client, data$df3) + th3 <- push_to_table(client, data$df3) th3 %>% bind_to_variable("table3") expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) - th4 <- as_dh_table(client, data$df4) + th4 <- push_to_table(client, data$df4) th4 %>% bind_to_variable("table4") expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) @@ -119,19 +119,19 @@ test_that("open_table opens the correct table from the server using |>", { client <- dhConnect(target = "localhost:10000") - th1 <- as_dh_table(client, data$df1) + th1 <- push_to_table(client, data$df1) th1 |> bind_to_variable("table1") expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) - th2 <- as_dh_table(client, data$df2) + th2 <- push_to_table(client, data$df2) th2 |> bind_to_variable("table2") expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) - th3 <- as_dh_table(client, data$df3) + th3 <- push_to_table(client, data$df3) th3 |> bind_to_variable("table3") expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) - th4 <- as_dh_table(client, data$df4) + th4 <- push_to_table(client, data$df4) th4 |> bind_to_variable("table4") expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) @@ -186,7 +186,27 @@ test_that("dhConnect fails nicely with bad inputs", { expect_error( dhConnect(target = "localhost:10000", auth_type = "basic"), - "Basic authentication was requested, but at least one of 'username' or 'password' was not provided." + "Basic authentication was requested, but 'auth_token' was not provided, and at most one of 'username' or 'password' was provided. Please provide either 'username' and 'password', or 'auth_token'." + ) + expect_error( + dhConnect(target = "localhost:10000", auth_type = "basic", username = "user"), + "Basic authentication was requested, but 'auth_token' was not provided, and at most one of 'username' or 'password' was provided. Please provide either 'username' and 'password', or 'auth_token'." + ) + expect_error( + dhConnect(target = "localhost:10000", auth_type = "basic", password = "pass"), + "Basic authentication was requested, but 'auth_token' was not provided, and at most one of 'username' or 'password' was provided. Please provide either 'username' and 'password', or 'auth_token'." + ) + expect_error( + dhConnect(target = "localhost:10000", auth_type = "basic", username = "user", auth_token = "token"), + "Basic authentication was requested, but 'auth_token' was provided, as well as least one of 'username' and 'password'. Please provide either 'username' and 'password', or 'auth_token'." + ) + expect_error( + dhConnect(target = "localhost:10000", auth_type = "basic", password = "pass", auth_token = "token"), + "Basic authentication was requested, but 'auth_token' was provided, as well as least one of 'username' and 'password'. Please provide either 'username' and 'password', or 'auth_token'." + ) + expect_error( + dhConnect(target = "localhost:10000", auth_type = "basic", username = "user", password = "pass", auth_token = "token"), + "Basic authentication was requested, but 'auth_token' was provided, as well as least one of 'username' and 'password'. Please provide either 'username' and 'password', or 'auth_token'." ) expect_error( dhConnect(target = "localhost:10000", auth_type = "custom"), @@ -198,7 +218,7 @@ test_that("dhConnect fails nicely with bad inputs", { ) expect_error( dhConnect(target = "localhost:10000", auth_type = "basic", auth_token = 1234), - "Basic authentication was requested, but at least one of 'username' or 'password' was not provided." + "'auth_token' must be a single string. Got an object of class numeric." ) expect_error( dhConnect(target = "localhost:10000", session_type = "blahblah"), @@ -227,20 +247,20 @@ test_that("dhConnect fails nicely with bad inputs", { }) -test_that("as_dh_table fails nicely with bad inputs", { +test_that("push_to_table fails nicely with bad inputs", { library(datasets) client <- dhConnect(target = "localhost:10000") - expect_error(as_dh_table(client, 12345), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"numeric\"’")) - expect_error(as_dh_table(client, "hello!"), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"character\"’")) + expect_error(push_to_table(client, 12345), cat("unable to find an inherited method for function ‘push_to_table’ for signature ‘\"Client\", \"numeric\"’")) + expect_error(push_to_table(client, "hello!"), cat("unable to find an inherited method for function ‘push_to_table’ for signature ‘\"Client\", \"character\"’")) # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. data(iris) - expect_error(as_dh_table(client, iris)) + expect_error(push_to_table(client, iris)) data(HairEyeColor) - expect_error(as_dh_table(client, HairEyeColor), cat("unable to find an inherited method for function ‘as_dh_table’ for signature ‘\"Client\", \"table\"’")) + expect_error(push_to_table(client, HairEyeColor), cat("unable to find an inherited method for function ‘push_to_table’ for signature ‘\"Client\", \"table\"’")) close(client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 4091bc6547d..28d7dd27d6c 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -26,10 +26,10 @@ setup <- function() { client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- as_dh_table(client, df1) - th2 <- as_dh_table(client, df2) - th3 <- as_dh_table(client, df3) - th4 <- as_dh_table(client, df4) + th1 <- push_to_table(client, df1) + th2 <- push_to_table(client, df2) + th3 <- push_to_table(client, df3) + th4 <- push_to_table(client, df4) # time table to test is_static() th5 <- time_table(client, 1000000000) %>% update("X = ii") diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 6e67bd072e4..3d44471421d 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -41,12 +41,12 @@ setup <- function() { client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- as_dh_table(client, df1) - th2 <- as_dh_table(client, df2) - th3 <- as_dh_table(client, df3) - th4 <- as_dh_table(client, df4) - th5 <- as_dh_table(client, df5) - th6 <- as_dh_table(client, df6) + th1 <- push_to_table(client, df1) + th2 <- push_to_table(client, df2) + th3 <- push_to_table(client, df3) + th4 <- push_to_table(client, df4) + th5 <- push_to_table(client, df5) + th6 <- push_to_table(client, df6) return(list( "client" = client, @@ -78,6 +78,9 @@ test_that("merge behaves as expected", { new_th5 <- merge(c(data$th5, data$th6, NULL, data$th6, data$th5)) expect_equal(as.data.frame(new_th5), new_df3) + new_th6 <- merge(data$th5, c(data$th6, data$th6, data$th5)) + expect_equal(as.data.frame(new_th6), new_df3) + close(data$client) }) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index 13d1f058426..f5256e68daf 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -241,7 +241,7 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.Merge(converted_sources)); }; - TableHandleWrapper* Sort(std::vector columnSpecs, std::vector descending, std::vector absCol) { + TableHandleWrapper* Sort(std::vector columnSpecs, std::vector descending, std::vector abs) { std::vector sort_pairs; sort_pairs.reserve(columnSpecs.size()); @@ -249,15 +249,15 @@ class TableHandleWrapper { descending = std::vector(columnSpecs.size(), descending[0]); } - if (absCol.size() == 1) { - absCol = std::vector(columnSpecs.size(), absCol[0]); + if (abs.size() == 1) { + abs = std::vector(columnSpecs.size(), abs[0]); } for(int i = 0; i < columnSpecs.size(); i++) { if (!descending[i]) { - sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], absCol[i])); + sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], abs[i])); } else { - sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], absCol[i])); + sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], abs[i])); } } @@ -329,8 +329,9 @@ class ClientOptionsWrapper { internal_options->SetDefaultAuthentication(); } - void SetBasicAuthentication(const std::string &username, const std::string &password) { - internal_options->SetBasicAuthentication(username, password); + void SetBasicAuthentication(const std::string &authentication_token) { + const std::string authentication_token_base64 = Base64Encode(authentication_token); + internal_options->SetCustomAuthentication("Basic", authentication_token_base64); } void SetCustomAuthentication(const std::string &authentication_type, const std::string &authentication_token) { From 79fb2a4114632e8542919700ef25d221aa21da11 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 15 Aug 2023 11:18:43 -0500 Subject: [PATCH 69/73] Kill merge, make merge_tables --- R/rdeephaven/NAMESPACE | 4 +- R/rdeephaven/R/table_ops.R | 68 +++---------------- .../inst/tests/testthat/test_table_ops.R | 14 ++-- 3 files changed, 17 insertions(+), 69 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index 069032db3ed..b687d4e5077 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -13,6 +13,7 @@ export(agg_std) export(agg_sum) export(agg_var) export(agg_w_avg) +export(merge_tables) export(sort) exportClasses(Aggregation) exportClasses(Client) @@ -22,7 +23,6 @@ exportMethods(agg_by) exportMethods(as.data.frame) exportMethods(as_arrow_table) exportMethods(as_data_frame) -exportMethods(push_to_table) exportMethods(as_record_batch_reader) exportMethods(as_tibble) exportMethods(avg_by) @@ -43,13 +43,13 @@ exportMethods(is_static) exportMethods(last_by) exportMethods(max_by) exportMethods(median_by) -exportMethods(merge) exportMethods(min_by) exportMethods(natural_join) exportMethods(ncol) exportMethods(nrow) exportMethods(open_table) exportMethods(percentile_by) +exportMethods(push_to_table) exportMethods(run_script) exportMethods(select) exportMethods(sort) diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 98f438e4c38..c46c3da172c 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -1,65 +1,13 @@ -setGeneric( - "merge", - function(x, y = NULL, ...) { - standardGeneric("merge") - } -) - -# We need many implementations of 'merge' because of the kind of args it should support - -base_merge <- function(x, y, ...) { - arg_list <- c(unlist(x), unlist(y), unlist(c(...))) - if (length(arg_list) == 1) { - return(arg_list[[1]]) - } - unwrapped_arg_list <- lapply(arg_list, strip_s4_wrapping) - return(new("TableHandle", .internal_rcpp_object = unwrapped_arg_list[[1]]$merge(unwrapped_arg_list[2:length(unwrapped_arg_list)]))) -} - -# supports merge(c(t1, t2, t3)) #' @export -setMethod( - "merge", - signature = c(x = "list", y = "missing"), - function(x, y = NULL) { - verify_type("x", x, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y)) - } -) - -# supports merge(t1) edge case -#' @export -setMethod( - "merge", - signature = c(x = "TableHandle", y = "missing"), - function(x, y = NULL) { - return(base_merge(x, y)) +merge_tables <- function(...) { + table_list <- unlist(c(...)) + verify_type("table_list", table_list, "TableHandle", "Deephaven TableHandle", FALSE) + if (length(table_list) == 1) { + return(table_list[[1]]) } -) - -# supports merge(t1, t2, t3) -#' @export -setMethod( - "merge", - signature = c(x = "TableHandle", y = "TableHandle"), - function(x, y, ...) { - if (length(c(...)) != 0) { - verify_type("...", c(...), "TableHandle", "Deephaven TableHandle", FALSE) - } - return(base_merge(x, y, c(...))) - } -) - -# supports merge(t1, c(t2, t3)) -#' @export -setMethod( - "merge", - signature = c(x = "TableHandle", y = "list"), - function(x, y) { - verify_type("y", y, "TableHandle", "Deephaven TableHandle", FALSE) - return(base_merge(x, y)) - } -) + unwrapped_table_list <- lapply(table_list, strip_s4_wrapping) + return(new("TableHandle", .internal_rcpp_object = unwrapped_table_list[[1]]$merge(unwrapped_table_list[2:length(unwrapped_table_list)]))) +} setGeneric( "select", diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 3d44471421d..50b0177b2e3 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -57,28 +57,28 @@ setup <- function() { ##### TESTING GOOD INPUTS ##### -test_that("merge behaves as expected", { +test_that("merge_tables behaves as expected", { data <- setup() new_df1 <- rbind(data$df5) - new_th1 <- merge(data$th5) + new_th1 <- merge_tables(data$th5) expect_equal(as.data.frame(new_th1), new_df1) new_df2 <- rbind(data$df5, data$df6) - new_th2 <- merge(data$th5, data$th6) + new_th2 <- merge_tables(data$th5, data$th6) expect_equal(as.data.frame(new_th2), new_df2) new_df3 <- rbind(data$df5, data$df6, data$df6, data$df5) - new_th3 <- merge(data$th5, data$th6, data$th6, data$th5) + new_th3 <- merge_tables(data$th5, data$th6, data$th6, data$th5) expect_equal(as.data.frame(new_th3), new_df3) - new_th4 <- merge(c(data$th5, data$th6)) + new_th4 <- merge_tables(c(data$th5, data$th6)) expect_equal(as.data.frame(new_th4), new_df2) - new_th5 <- merge(c(data$th5, data$th6, NULL, data$th6, data$th5)) + new_th5 <- merge_tables(c(data$th5, data$th6, NULL, data$th6, data$th5)) expect_equal(as.data.frame(new_th5), new_df3) - new_th6 <- merge(data$th5, c(data$th6, data$th6, data$th5)) + new_th6 <- merge_tables(data$th5, c(data$th6, data$th6, data$th5)) expect_equal(as.data.frame(new_th6), new_df3) close(data$client) From e8eb704078b76017b0882e283b78baa3be2ac083 Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 15 Aug 2023 11:20:16 -0500 Subject: [PATCH 70/73] Update version --- R/rdeephaven/DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/rdeephaven/DESCRIPTION b/R/rdeephaven/DESCRIPTION index ed89c74e251..c255c760014 100644 --- a/R/rdeephaven/DESCRIPTION +++ b/R/rdeephaven/DESCRIPTION @@ -1,7 +1,7 @@ Package: rdeephaven Type: Package Title: R Client for Deephaven Core -Version: 0.26.0 +Version: 0.27.1 Date: 2023-05-12 Author: Deephaven Data Labs Maintainer: Alex Peters From c782b60441c78692e32395f63071e546ea08282f Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 15 Aug 2023 11:28:25 -0500 Subject: [PATCH 71/73] Change to abs_sort --- R/rdeephaven/R/table_ops.R | 12 ++++++------ R/rdeephaven/src/client.cpp | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index c46c3da172c..3cdef49a2ad 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -518,7 +518,7 @@ setMethod( #' @export setGeneric( "sort", - function(table_handle, by = character(), descending = FALSE, abs_col = FALSE, ...) { + function(table_handle, by = character(), descending = FALSE, abs_sort = FALSE, ...) { standardGeneric("sort") }, signature = c("table_handle", "by", "descending") @@ -528,16 +528,16 @@ setGeneric( setMethod( "sort", signature = c(table_handle = "TableHandle"), - function(table_handle, by, descending = FALSE, abs_col = FALSE) { + function(table_handle, by, descending = FALSE, abs_sort = FALSE) { verify_string("by", by, FALSE) verify_bool("descending", descending, FALSE) - verify_bool("abs_col", abs_col, FALSE) + verify_bool("abs_sort", abs_sort, FALSE) if ((length(descending) > 1) && length(descending) != length(by)) { stop(paste0("'descending' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'descending' with length ", length(descending), ".")) } - if ((length(abs_col) > 1) && length(abs_col) != length(by)) { - stop(paste0("'abs_col' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'abs_col' with length ", length(abs_col), ".")) + if ((length(abs_sort) > 1) && length(abs_sort) != length(by)) { + stop(paste0("'abs_sort' must be the same length as 'by' if more than one entry is supplied. Got 'by' with length ", length(by), " and 'abs_sort' with length ", length(abs_sort), ".")) } - return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(by, descending, abs_col))) + return(new("TableHandle", .internal_rcpp_object = table_handle@.internal_rcpp_object$sort(by, descending, abs_sort))) } ) diff --git a/R/rdeephaven/src/client.cpp b/R/rdeephaven/src/client.cpp index f5256e68daf..bd8b386ce3e 100644 --- a/R/rdeephaven/src/client.cpp +++ b/R/rdeephaven/src/client.cpp @@ -241,7 +241,7 @@ class TableHandleWrapper { return new TableHandleWrapper(internal_tbl_hdl.Merge(converted_sources)); }; - TableHandleWrapper* Sort(std::vector columnSpecs, std::vector descending, std::vector abs) { + TableHandleWrapper* Sort(std::vector columnSpecs, std::vector descending, std::vector absSort) { std::vector sort_pairs; sort_pairs.reserve(columnSpecs.size()); @@ -249,15 +249,15 @@ class TableHandleWrapper { descending = std::vector(columnSpecs.size(), descending[0]); } - if (abs.size() == 1) { - abs = std::vector(columnSpecs.size(), abs[0]); + if (absSort.size() == 1) { + absSort = std::vector(columnSpecs.size(), absSort[0]); } for(int i = 0; i < columnSpecs.size(); i++) { if (!descending[i]) { - sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], abs[i])); + sort_pairs.push_back(deephaven::client::SortPair::Ascending(columnSpecs[i], absSort[i])); } else { - sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], abs[i])); + sort_pairs.push_back(deephaven::client::SortPair::Descending(columnSpecs[i], absSort[i])); } } From f88237c2e41004d691225b03c79478fc90a8e38a Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 15 Aug 2023 12:05:27 -0500 Subject: [PATCH 72/73] Support merge_tables(NULL) --- R/rdeephaven/R/client_wrapper.R | 2 +- R/rdeephaven/R/table_ops.R | 3 +++ R/rdeephaven/inst/tests/testthat/test_table_ops.R | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index aaede75cc93..f0c39b243a6 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -117,7 +117,7 @@ setMethod( } if ((tls_root_certs != "") && (use_tls == FALSE)) { - warning("'tls_root_certs' was set but it will not be used, as 'use_tls is FALSE.") + warning("'tls_root_certs' was set but it will not be used, as 'use_tls' is FALSE.") } internal_client <- new(INTERNAL_Client, diff --git a/R/rdeephaven/R/table_ops.R b/R/rdeephaven/R/table_ops.R index 3cdef49a2ad..40bea013348 100644 --- a/R/rdeephaven/R/table_ops.R +++ b/R/rdeephaven/R/table_ops.R @@ -1,6 +1,9 @@ #' @export merge_tables <- function(...) { table_list <- unlist(c(...)) + if (length(table_list) == 0) { + return(NULL) + } verify_type("table_list", table_list, "TableHandle", "Deephaven TableHandle", FALSE) if (length(table_list) == 1) { return(table_list[[1]]) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 50b0177b2e3..374cd3d29d0 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -60,6 +60,8 @@ setup <- function() { test_that("merge_tables behaves as expected", { data <- setup() + expect_equal(NULL, merge_tables(NULL)) + new_df1 <- rbind(data$df5) new_th1 <- merge_tables(data$th5) expect_equal(as.data.frame(new_th1), new_df1) From 794ef84df394f948bd65d3c720dec8f424e0d32b Mon Sep 17 00:00:00 2001 From: alexpeters1208 Date: Tue, 15 Aug 2023 14:28:03 -0500 Subject: [PATCH 73/73] Change push_to_table to import_table --- R/rdeephaven/NAMESPACE | 2 +- R/rdeephaven/R/client_wrapper.R | 18 ++--- .../inst/tests/testthat/test_agg_by.R | 12 ++-- .../inst/tests/testthat/test_client_wrapper.R | 68 +++++++++---------- .../testthat/test_table_handle_wrapper.R | 8 +-- .../inst/tests/testthat/test_table_ops.R | 12 ++-- 6 files changed, 60 insertions(+), 60 deletions(-) diff --git a/R/rdeephaven/NAMESPACE b/R/rdeephaven/NAMESPACE index b687d4e5077..40eb78d6810 100644 --- a/R/rdeephaven/NAMESPACE +++ b/R/rdeephaven/NAMESPACE @@ -49,7 +49,7 @@ exportMethods(ncol) exportMethods(nrow) exportMethods(open_table) exportMethods(percentile_by) -exportMethods(push_to_table) +exportMethods(import_table) exportMethods(run_script) exportMethods(select) exportMethods(sort) diff --git a/R/rdeephaven/R/client_wrapper.R b/R/rdeephaven/R/client_wrapper.R index f0c39b243a6..6b4be652c07 100644 --- a/R/rdeephaven/R/client_wrapper.R +++ b/R/rdeephaven/R/client_wrapper.R @@ -195,16 +195,16 @@ setMethod( ) setGeneric( - "push_to_table", + "import_table", function(client_instance, table_object) { - return(standardGeneric("push_to_table")) + return(standardGeneric("import_table")) }, signature = c("client_instance", "table_object") ) #' @export setMethod( - "push_to_table", + "import_table", signature = c(client_instance = "Client", table_object = "RecordBatchReader"), function(client_instance, table_object) { ptr <- client_instance@.internal_rcpp_object$new_arrow_array_stream_ptr() @@ -219,28 +219,28 @@ setMethod( #' @export setMethod( - "push_to_table", + "import_table", signature = c(client_instance = "Client", table_object = "Table"), function(client_instance, table_object) { - return(push_to_table(client_instance, as_record_batch_reader(table_object))) + return(import_table(client_instance, as_record_batch_reader(table_object))) } ) #' @export setMethod( - "push_to_table", + "import_table", signature = c(client_instance = "Client", table_object = "tbl_df"), function(client_instance, table_object) { - return(push_to_table(client_instance, arrow_table(table_object))) + return(import_table(client_instance, arrow_table(table_object))) } ) #' @export setMethod( - "push_to_table", + "import_table", signature = c(client_instance = "Client", table_object = "data.frame"), function(client_instance, table_object) { - return(push_to_table(client_instance, arrow_table(table_object))) + return(import_table(client_instance, arrow_table(table_object))) } ) diff --git a/R/rdeephaven/inst/tests/testthat/test_agg_by.R b/R/rdeephaven/inst/tests/testthat/test_agg_by.R index d14fa6b7cd1..2480fffd74b 100644 --- a/R/rdeephaven/inst/tests/testthat/test_agg_by.R +++ b/R/rdeephaven/inst/tests/testthat/test_agg_by.R @@ -41,12 +41,12 @@ setup <- function() { client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- push_to_table(client, df1) - th2 <- push_to_table(client, df2) - th3 <- push_to_table(client, df3) - th4 <- push_to_table(client, df4) - th5 <- push_to_table(client, df5) - th6 <- push_to_table(client, df6) + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) + th5 <- import_table(client, df5) + th6 <- import_table(client, df6) return(list( "client" = client, diff --git a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R index a3a25b7759a..9e779e2a7d7 100644 --- a/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_client_wrapper.R @@ -34,59 +34,59 @@ test_that("client dhConnection works in the simple case of anonymous authenticat }) -test_that("push_to_table does not fail with data frame inputs of simple column types", { +test_that("import_table does not fail with data frame inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(push_to_table(client, data$df1)) - expect_no_error(push_to_table(client, data$df2)) - expect_no_error(push_to_table(client, data$df3)) - expect_no_error(push_to_table(client, data$df4)) + expect_no_error(import_table(client, data$df1)) + expect_no_error(import_table(client, data$df2)) + expect_no_error(import_table(client, data$df3)) + expect_no_error(import_table(client, data$df4)) close(client) }) -test_that("push_to_table does not fail with tibble inputs of simple column types", { +test_that("import_table does not fail with tibble inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(push_to_table(client, as_tibble(data$df1))) - expect_no_error(push_to_table(client, as_tibble(data$df2))) - expect_no_error(push_to_table(client, as_tibble(data$df3))) - expect_no_error(push_to_table(client, as_tibble(data$df4))) + expect_no_error(import_table(client, as_tibble(data$df1))) + expect_no_error(import_table(client, as_tibble(data$df2))) + expect_no_error(import_table(client, as_tibble(data$df3))) + expect_no_error(import_table(client, as_tibble(data$df4))) close(client) }) -test_that("push_to_table does not fail with arrow table inputs of simple column types", { +test_that("import_table does not fail with arrow table inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(push_to_table(client, as_arrow_table(data$df1))) - expect_no_error(push_to_table(client, as_arrow_table(data$df2))) - expect_no_error(push_to_table(client, as_arrow_table(data$df3))) - expect_no_error(push_to_table(client, as_arrow_table(data$df4))) + expect_no_error(import_table(client, as_arrow_table(data$df1))) + expect_no_error(import_table(client, as_arrow_table(data$df2))) + expect_no_error(import_table(client, as_arrow_table(data$df3))) + expect_no_error(import_table(client, as_arrow_table(data$df4))) close(client) }) -test_that("push_to_table does not fail with record batch reader inputs of simple column types", { +test_that("import_table does not fail with record batch reader inputs of simple column types", { data <- setup() client <- dhConnect(target = "localhost:10000") - expect_no_error(push_to_table(client, as_record_batch_reader(data$df1))) - expect_no_error(push_to_table(client, as_record_batch_reader(data$df2))) - expect_no_error(push_to_table(client, as_record_batch_reader(data$df3))) - expect_no_error(push_to_table(client, as_record_batch_reader(data$df4))) + expect_no_error(import_table(client, as_record_batch_reader(data$df1))) + expect_no_error(import_table(client, as_record_batch_reader(data$df2))) + expect_no_error(import_table(client, as_record_batch_reader(data$df3))) + expect_no_error(import_table(client, as_record_batch_reader(data$df4))) close(client) }) -# The following tests assume the correctness of push_to_table(...) AND bind_to_variable(), +# The following tests assume the correctness of import_table(...) AND bind_to_variable(), # as we have to create data, push it to the server, and name it in order to test open_table(). # Additionally, we assume the correctness of as.data.frame() to make concrete comparisons. @@ -95,19 +95,19 @@ test_that("open_table opens the correct table from the server using %>%", { client <- dhConnect(target = "localhost:10000") - th1 <- push_to_table(client, data$df1) + th1 <- import_table(client, data$df1) th1 %>% bind_to_variable("table1") expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) - th2 <- push_to_table(client, data$df2) + th2 <- import_table(client, data$df2) th2 %>% bind_to_variable("table2") expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) - th3 <- push_to_table(client, data$df3) + th3 <- import_table(client, data$df3) th3 %>% bind_to_variable("table3") expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) - th4 <- push_to_table(client, data$df4) + th4 <- import_table(client, data$df4) th4 %>% bind_to_variable("table4") expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) @@ -119,19 +119,19 @@ test_that("open_table opens the correct table from the server using |>", { client <- dhConnect(target = "localhost:10000") - th1 <- push_to_table(client, data$df1) + th1 <- import_table(client, data$df1) th1 |> bind_to_variable("table1") expect_equal(as.data.frame(open_table(client, "table1")), as.data.frame(th1)) - th2 <- push_to_table(client, data$df2) + th2 <- import_table(client, data$df2) th2 |> bind_to_variable("table2") expect_equal(as.data.frame(open_table(client, "table2")), as.data.frame(th2)) - th3 <- push_to_table(client, data$df3) + th3 <- import_table(client, data$df3) th3 |> bind_to_variable("table3") expect_equal(as.data.frame(open_table(client, "table3")), as.data.frame(th3)) - th4 <- push_to_table(client, data$df4) + th4 <- import_table(client, data$df4) th4 |> bind_to_variable("table4") expect_equal(as.data.frame(open_table(client, "table4")), as.data.frame(th4)) @@ -247,20 +247,20 @@ test_that("dhConnect fails nicely with bad inputs", { }) -test_that("push_to_table fails nicely with bad inputs", { +test_that("import_table fails nicely with bad inputs", { library(datasets) client <- dhConnect(target = "localhost:10000") - expect_error(push_to_table(client, 12345), cat("unable to find an inherited method for function ‘push_to_table’ for signature ‘\"Client\", \"numeric\"’")) - expect_error(push_to_table(client, "hello!"), cat("unable to find an inherited method for function ‘push_to_table’ for signature ‘\"Client\", \"character\"’")) + expect_error(import_table(client, 12345), cat("unable to find an inherited method for function ‘import_table’ for signature ‘\"Client\", \"numeric\"’")) + expect_error(import_table(client, "hello!"), cat("unable to find an inherited method for function ‘import_table’ for signature ‘\"Client\", \"character\"’")) # TODO: this needs better error handling, but it is unclear whether that happens on the server side or the R side. data(iris) - expect_error(push_to_table(client, iris)) + expect_error(import_table(client, iris)) data(HairEyeColor) - expect_error(push_to_table(client, HairEyeColor), cat("unable to find an inherited method for function ‘push_to_table’ for signature ‘\"Client\", \"table\"’")) + expect_error(import_table(client, HairEyeColor), cat("unable to find an inherited method for function ‘import_table’ for signature ‘\"Client\", \"table\"’")) close(client) }) diff --git a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R index 28d7dd27d6c..49fa4ab12ba 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_handle_wrapper.R @@ -26,10 +26,10 @@ setup <- function() { client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- push_to_table(client, df1) - th2 <- push_to_table(client, df2) - th3 <- push_to_table(client, df3) - th4 <- push_to_table(client, df4) + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) # time table to test is_static() th5 <- time_table(client, 1000000000) %>% update("X = ii") diff --git a/R/rdeephaven/inst/tests/testthat/test_table_ops.R b/R/rdeephaven/inst/tests/testthat/test_table_ops.R index 374cd3d29d0..7cbfda33d93 100644 --- a/R/rdeephaven/inst/tests/testthat/test_table_ops.R +++ b/R/rdeephaven/inst/tests/testthat/test_table_ops.R @@ -41,12 +41,12 @@ setup <- function() { client <- dhConnect(target = "localhost:10000") # move dataframes to server and get TableHandles for testing - th1 <- push_to_table(client, df1) - th2 <- push_to_table(client, df2) - th3 <- push_to_table(client, df3) - th4 <- push_to_table(client, df4) - th5 <- push_to_table(client, df5) - th6 <- push_to_table(client, df6) + th1 <- import_table(client, df1) + th2 <- import_table(client, df2) + th3 <- import_table(client, df3) + th4 <- import_table(client, df4) + th5 <- import_table(client, df5) + th6 <- import_table(client, df6) return(list( "client" = client,