Skip to content

Commit

Permalink
Update R6 class documentation in R Client (deephaven#3939)
Browse files Browse the repository at this point in the history
* Update R6 class documentation

* Create readme for the R client outline installation

* Delete README.md

* Apply suggestions from code review

Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: margaretkennedy <82049573+margaretkennedy@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: margaretkennedy <82049573+margaretkennedy@users.noreply.github.com>

* Update client_options_wrapper docs

* Update client_wrapper docs

* Update table_handle_wrapper docs

* Update Client.Rd

* Update ClientOptions.Rd

* Update TableHandle.Rd

* Delete rdeephaven-package.Rd

* Remove explicit methods from client_options_wrapper

* Remove explicit methods from client_wrapper

* Remove explicit methods from table_handle_wrapper

* Add readme

* Update README.md

* Remove we/you from README

* Apply suggestions from code review

Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com>

* Apply Chip's suggestions to README

* Add instructions for git sparse-checkout

* Remove redundancy

* Apply suggestions from code review

Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com>

* More suggestions to README

---------

Co-authored-by: Chip Kent <5250374+chipkent@users.noreply.github.com>
Co-authored-by: margaretkennedy <82049573+margaretkennedy@users.noreply.github.com>
  • Loading branch information
3 people committed Jun 14, 2023
1 parent 2e90912 commit 96954d1
Show file tree
Hide file tree
Showing 8 changed files with 343 additions and 79 deletions.
47 changes: 32 additions & 15 deletions R/rdeephaven/R/client_options_wrapper.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,74 @@
#' 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, we support three different kinds of authentication that your Deephaven server might be using:
#' 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 you are
#' running the Deephaven server locally, this is probably the kind of authentication you are using.
#' - "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 your authentication parameters when you connect to a client, you can also start
#' a console in one of our supported server languages. We currently support Python and Groovy, and if you
#' want start a console upon client connection, you must ensure that the server you're connecting to was
#' started with support for the language you want to use.
#' 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.
#'
#' @section Methods
#'
#' - `$set_default_authentication()`
#' - `$set_basic_authentication()`
#' - `$set_custom_authentication()`
#' @usage NULL
#' @format NULL
#' @docType class
#'
#' @examples
#'
#' # connect to the Deephaven server running on "localhost:10000" with anonymous 'default' authentication
#' # connect to a Deephaven server with a Python console running on "localhost:10000" using anonymous 'default' authentication
#' client_options <- ClientOptions$new()
#' client_options$set_default_authentication()
#' 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)


ClientOptions <- R6Class("ClientOptions",
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) {
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) {
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) {
self$internal_client_options$set_session_type(session_type)
},

internal_client_options = NULL
)
)
)
17 changes: 5 additions & 12 deletions R/rdeephaven/R/client_wrapper.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,11 @@
#' @usage NULL
#' @format NULL
#' @docType class
#'
#' @section Methods
#'
#' - `$open_table(name)`
#' - `$import_table(table_object)`
#' - `$run_script(script)`
#'
#' @examples
#'
#' # connect to the Deephaven server running on "localhost:10000" with anonymous 'default' authentication
#' # connect to the Deephaven server running on "localhost:10000" using anonymous 'default' authentication
#' client_options <- ClientOptions$new()
#' client_options$set_default_authentication()
#' client <- Client$new(target="localhost:10000", client_options=client_options)
#'
#' # open a table that already exists on the server
Expand Down Expand Up @@ -45,7 +38,7 @@ Client <- R6Class("Client",

#' @description
#' Opens a table named 'name' from the server if it exists.
#' @param name Name of the table to open from the server as a string.
#' @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) {
private$verify_string(name, "name")
Expand All @@ -58,7 +51,7 @@ Client <- R6Class("Client",
#' @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, an R Tibble, an Arrow Table, or an Arrow RecordBatchReader
#' @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) {
Expand All @@ -78,14 +71,14 @@ Client <- R6Class("Client",
return(TableHandle$new(private$arrow_to_dh_table(table_object)))
}
else {
stop(paste0("'table_object' must be either an R Data Frame, an R Tibble, an Arrow Table, or an Arrow Record Batch Reader.
stop(paste0("'table_object' must be either an R Data Frame, a dplyr Tibble, an Arrow Table, or an Arrow Record Batch Reader.
Got 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 as a string.
#' @param script Code to be executed on the server, passed as a string.
run_script = function(script) {
private$verify_string(script, "script")
private$internal_client$run_script(script)
Expand Down
48 changes: 44 additions & 4 deletions R/rdeephaven/R/table_handle_wrapper.R
Original file line number Diff line number Diff line change
@@ -1,46 +1,86 @@
# TODO: Document this guy

#' @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")

TableHandle <- R6Class("TableHandle",
public = list(

initialize = function(table_handle) {

if (class(table_handle)[[1]] != "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.")
}
private$internal_table_handle <- table_handle
},

#' @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) {
if (class(name)[[1]] != "character") {
stop(paste("'name' should be a character or a string. Got object of type ", class(name)[[1]], " instead."))
}
private$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()
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 dataframe
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
}

),
Expand Down
75 changes: 75 additions & 0 deletions R/rdeephaven/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# The Deephaven R Client

The Deephaven R client is an R package that enables R users to interface with a Deephaven server and perform various
server-side operations from the comfort of RStudio or any other R interface.

## What can the R client do?

The Deephaven Client currently provides three basic functionalities:

1. Connect to a Deephaven server
- with anonymous authentication (no username or password)
- with basic authentication (username and password)
- with custom authentication (general key-value credentials)

2. Interface with Deephaven Tables on the server
- Retrieve references to tables on the server
- Pull table data into an [Arrow RecordBatchReader](https://arrow.apache.org/docs/r/reference/RecordBatchReader.html),
an [Arrow Table](https://arrow.apache.org/docs/r/reference/Table.html),
a [dplyr Tibble](https://tibble.tidyverse.org),
or an [R Data Frame](https://stat.ethz.ch/R-manual/R-devel/library/base/html/data.frame.html)
- Create new tables on the server from an [Arrow RecordBatchReader](https://arrow.apache.org/docs/r/reference/RecordBatchReader.html),
an [Arrow Table](https://arrow.apache.org/docs/r/reference/Table.html),
a [dplyr Tibble](https://tibble.tidyverse.org),
or an [R Data Frame](https://stat.ethz.ch/R-manual/R-devel/library/base/html/data.frame.html)
- Bind server-side tables to variable names, enabling access from outside the current R session

3. Run scripts on the server
- If the server is equipped with a console, run a script in that console
- Currently, Python and Groovy are supported

## Installation

Currently, the R client is only supported on Ubuntu 20.04 or 22.04 and must be built from source.

1. Choose a directory where the client source code will live. Here, the source code will be downloaded into a new directory called `deephaven`.
Navigate into that directory and clone this subdirectory of `deephaven-core` using git's sparse-checkout:
```bash
mkdir deephaven
cd deephaven
git init
git remote add -f origin https://github.com/deephaven/deephaven-core.git
git config core.sparseCheckout true
echo "R/rdeephaven" >> .git/info/sparse-checkout
git pull origin main
```
2. Now, navigate into the source code `lib` directory and build the C++ client and dependencies:
```bash
cd R/rdeephaven/lib
chmod +x build-cpp.sh
./build-cpp.sh
```
3. With the C++ client installed, start an R console with this command:
```bash
R
```
and in that console, install the client:
```r
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.
5. Now, run
```r
library(rdeephaven)
```
in the R session, and start using the client!

## High-level design overview

The R client uses the
[Deephaven C++ client](https://github.com/deephaven/deephaven-core/tree/main/cpp-client)
as the backend for connecting to and communicating with the server. Any Deephaven-specific feature in the R client is,
at some level, an API for an equivalent feature in the C++ client.
To make Deephaven's C++ client API available in R, an R6 class provides an R interface to
[Rcpp](https://github.com/RcppCore/Rcpp) wrapped parts of the C++ API. Deephaven's C++ API can create Arrow tables, and R has an [Arrow library](https://github.com/apache/arrow/tree/main/r). Because Arrow is an in-memory data format, Arrow data can be transferred between R and C++ simply by passing a pointer between the languages and using the
[Arrow C Stream Interface](https://arrow.apache.org/docs/format/CStreamInterface.html). No data copies are required.
9 changes: 4 additions & 5 deletions R/rdeephaven/man/Client.Rd

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

Loading

0 comments on commit 96954d1

Please sign in to comment.