| Title: | Work with Self-Hosted 'SeaTable' Servers and Data Files |
|---|---|
| Description: | An unofficial R client for self-hosted 'SeaTable' servers and for reading and writing 'SeaTable' data files directly. Reads a local '.dtable' export with no server at all, and talks to a self-hosted server over its REST (representational state transfer) application programming interface (API), returning tables, rows, columns and views as tidy 'tibble' objects through a column-type-aware coercion layer. Includes helpers for managing bases and files, converters to and from spreadsheet formats, and an optional 'shiny' explorer for interactive inspection. The 'SeaTable' API is documented at <https://api.seatable.com/>. This is an independent, third-party client: it is not affiliated with, endorsed by, or otherwise connected to SeaTable GmbH, and 'SeaTable' is their trademark, used here only to identify the software the package works with. |
| Authors: | Raban Heller [aut, cre, cph] (ORCID: <https://orcid.org/0000-0001-8006-9742>), Paul Elsinghorst [aut], Wiebke Derz [aut], Matthias Ring [aut], Gerhard Achatz [aut], Vinzent Forstmeier [aut] |
| Maintainer: | Raban Heller <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-11-03 18:08:57 UTC |
| Source: | https://github.com/CTTIR/harbouR |
Coerce a dtable's table index to a tibble
## S3 method for class 'harbour_dtable' as_tibble(x, ...)## S3 method for class 'harbour_dtable' as_tibble(x, ...)
x |
A |
... |
These dots are for future extensions and must be empty. |
A tibble with one row per table and columns name (chr),
n_rows (int), n_columns (int) and n_views (int). Unlike the
server path, the row count is real: the rows are in the file.
Other dtable:
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
tibble::as_tibble(hb_dtable(Samples = data.frame(x = 1)))tibble::as_tibble(hb_dtable(Samples = data.frame(x = 1)))
Coerce harbour metadata to a tibble
## S3 method for class 'harbour_metadata' as_tibble(x, ...)## S3 method for class 'harbour_metadata' as_tibble(x, ...)
x |
A |
... |
These dots are for future extensions and must be empty. |
A tibble with one row per table; see hb_list_tables().
Other metadata:
hb_column_types(),
hb_list_collaborators(),
hb_list_tables(),
hb_metadata(),
is_harbour_metadata(),
print.harbour_metadata(),
summary.harbour_metadata()
tibble::as_tibble(hb_example_metadata())tibble::as_tibble(hb_example_metadata())
Every error harbouR raises itself, and every HTTP or transport failure,
carries the class harbour_error, plus a more specific subclass, so
callers can react to what went wrong rather than matching on message
text. Errors from argument matching in rlang - a value that is not one
of an argument's choices, or an argument passed in ... that the
function does not have - keep the classes rlang gives them.
harbour_error_authCredentials are missing, malformed, or
were rejected by the server. Fields: status, url and
response_body when the server refused them; none when the
problem was caught before any request. The token exchanges refuse
credentials with whatever status their endpoint uses - a wrong
password is HTTP 400, an unknown API token HTTP 403 - and such an
error carries harbour_error_http or harbour_error_permission
as well.
harbour_error_httpThe server returned a non-2xx status that
has no more specific subclass, or the request got no complete
answer (status NA). Fields: status, url and response_body -
the parsed JSON, or the text when the server did not send JSON. It
is also raised for a redirect (a 3xx status), which harbouR reports
rather than follows, and for a reply that is not JSON whatever its
status, a 2xx included; response_body then holds the start of its
text. A
request that got no answer - a refused connection, a DNS or TLS
failure, a timeout, a dropped connection - also carries httr2's
classes httr2_failure and httr2_error, and has no
response_body. After a timeout or a dropped connection the server
may already have applied a write, so a status of NA alone does
not make sending the write again safe.
harbour_error_not_foundHTTP 404, or a named table, view or
column that does not exist in the base. Fields: status, url,
response_body for the HTTP case.
harbour_error_permissionHTTP 403. The token is not allowed
to do this. Fields: status, url, response_body.
harbour_error_rate_limitHTTP 429. Fields: status, url,
response_body.
harbour_error_bad_argumentAn argument failed validation before any request was made. Fields: none.
harbour_error_unsupportedThe operation is not available - for example an auth mode that this endpoint does not accept.
harbour_error_column_collisionA column in the data would collide with a reserved SeaTable field name.
harbour_error_package_assetA packaged branding asset is
missing from the installation. Field: file.
All of them also inherit from harbour_error and from rlang_error.
The warnings a script may want to check for, or to silence, carry a
class of their own, and inherit from rlang_warning:
harbour_warning_unknown_columnhb_append_rows() was given
columns the table does not have, and drops them.
harbour_warning_hidden_columnshb_read_table() read
through a view on a server, which leaves the columns the view hides
out of its rows, so they are NA.
harbour_warning_view_filtershb_read_table() read through
a filtered view of a .dtable file that records no rows for it, so
every row was returned.
harbour_warning_query_limithb_query() ran SQL without a
LIMIT clause, so SeaTable returned at most 100 rows.
harbour_warning_non_finitehb_append_rows() or
hb_update_rows() sent Inf, -Inf or NaN, which JSON cannot
hold, as null. Field: columns.
harbour_warning_checkbox_valuehb_append_rows() or
hb_update_rows() sent a checkbox string that as.logical() cannot
read as TRUE or FALSE as null. Field: columns.
harbour_warning_asset_linkhb_write_dtable() left symbolic
links in the asset tree, including a linked asset root, out of the
archive.
harbour_warning_dtable_tzhb_read_table() read date-times
from a .dtable that carry no time zone, as a server's export
stores them, as UTC, because options(harbouR.dtable_tz) names
none. Given once a session.
harbour_warning_json_keyshb_write_dtable() met object
keys that JSON cannot keep - empty, or repeated - so those values
change on the way to disk.
harbour_warning_json_texthb_read_dtable() met a NUL
character in content.json, which R cannot keep in a string.
harbour_warning_missing_assetshb_write_dtable() could not
include recorded attachments whose extracted files are missing.
Field: files, their filenames inside the archive.
harbour_warning_id_columnhb_dtable(), hb_read_csv() or
hb_read_xlsx()
dropped a column named _id that held values other than SeaTable
row ids.
res <- tryCatch( hb_client(server = "https://example.org", api_token = NULL), harbour_error_auth = function(cnd) "no credentials" ) resres <- tryCatch( hb_client(server = "https://example.org", api_token = NULL), harbour_error_auth = function(cnd) "no credentials" ) res
Add a column to a table
hb_add_column(client, table, name, type, ..., column_data = NULL)hb_add_column(client, table, name, type, ..., column_data = NULL)
client |
A |
table |
Table name. |
name |
Column name. |
type |
SeaTable column type, e.g. |
... |
These dots are for future extensions and must be empty. |
column_data |
Optional list of column options, e.g. the choices
for a select column. Named |
Invisibly returns the client.
Other columns:
hb_add_columns(),
hb_add_select_option(),
hb_delete_column(),
hb_delete_select_option(),
hb_list_columns(),
hb_update_column(),
hb_update_select_option()
## Not run: client <- hb_client() hb_add_column(client, "Samples", "Notes", "text") ## End(Not run)## Not run: client <- hb_client() hb_add_column(client, "Samples", "Notes", "text") ## End(Not run)
The columns are sent in one request. SeaTable's batch endpoint skips some column types without an error - a formula column among them - so any column its reply leaves out is then created on its own.
hb_add_columns(client, table, columns, ...)hb_add_columns(client, table, columns, ...)
client |
A |
table |
Table name. |
columns |
A list of column specs, each a named list with |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other columns:
hb_add_column(),
hb_add_select_option(),
hb_delete_column(),
hb_delete_select_option(),
hb_list_columns(),
hb_update_column(),
hb_update_select_option()
## Not run: client <- hb_client() hb_add_columns( client, "Samples", list( list(name = "a", type = "text"), list(name = "b", type = "number") ) ) ## End(Not run)## Not run: client <- hb_client() hb_add_columns( client, "Samples", list( list(name = "a", type = "text"), list(name = "b", type = "number") ) ) ## End(Not run)
The option is created in amber, with dark text: SeaTable requires both colours. Change them in SeaTable if you prefer others.
hb_add_select_option(client, table, name, option, ...)hb_add_select_option(client, table, name, option, ...)
client |
A |
table |
Table name. |
name |
Column name. |
option |
Option name to add. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other columns:
hb_add_column(),
hb_add_columns(),
hb_delete_column(),
hb_delete_select_option(),
hb_list_columns(),
hb_update_column(),
hb_update_select_option()
## Not run: client <- hb_client() hb_add_select_option(client, "Samples", "Status", "Done") ## End(Not run)## Not run: client <- hb_client() hb_add_select_option(client, "Samples", "Status", "Done") ## End(Not run)
Append rows to a table
hb_append_rows(client, table, data, ..., chunk_size = 1000L)hb_append_rows(client, table, data, ..., chunk_size = 1000L)
client |
A |
table |
Table name. |
data |
A tibble or data frame whose columns match the table schema. |
... |
These dots are for future extensions and must be empty. |
chunk_size |
Rows per request. SeaTable caps batch writes at 1000 and harbouR clamps it, warning if you asked for more. |
Invisibly, a one-row tibble with columns table (chr),
n_rows (int) - the count the server confirmed, or the number of
rows sent when its reply gives none - and
n_requests (int). The server's reply also lists the new rows'
_ids; harbouR's summary does not include them.
Other rows:
hb_delete_rows(),
hb_get_row(),
hb_lock_rows(),
hb_query(),
hb_read_table(),
hb_unlock_rows(),
hb_update_rows()
## Not run: client <- hb_client() hb_append_rows(client, "Samples", tibble::tibble(Name = "S1")) ## End(Not run)## Not run: client <- hb_client() hb_append_rows(client, "Samples", tibble::tibble(Name = "S1")) ## End(Not run)
Attachment cells in an export point at
file://dtable-bundle/asset/.... When the base was read with
assets = "extract", this gives the path the file was extracted to.
The URL may be escaped, as SeaTable's export writes it -
my%20report%20%281%29.txt for my report (1).txt.
hb_asset_path(x, url, ...)hb_asset_path(x, url, ...)
x |
A |
url |
An asset URL taken from a |
... |
These dots are for future extensions and must be empty. |
A single path, or NA_character_ if the asset is not bundled.
Other dtable:
as_tibble.harbour_dtable(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
path <- system.file("extdata", "example.dtable", package = "harbouR") base <- hb_read_dtable(path, assets = "extract") hb_asset_path(base, "file://dtable-bundle/asset/files/2026-07/readme.txt")path <- system.file("extdata", "example.dtable", package = "harbouR") base <- hb_read_dtable(path, assets = "extract") hb_asset_path(base, "file://dtable-bundle/asset/files/2026-07/readme.txt")
Convenience: uploads path then writes it into the given file or image
column of the chosen row. A file column receives the file object; an
image column, which holds URLs, receives the image's URL.
hb_attach_file(client, table, row_id, column, path, ...)hb_attach_file(client, table, row_id, column, path, ...)
client |
A |
table |
Table name. |
row_id |
Row ID. |
column |
File or image column name. |
path |
Local file path. Must exist. |
... |
These dots are for future extensions and must be empty. |
The cell is replaced, not appended to: whatever it held before is
no longer referenced by the row, although the earlier upload stays in
the base's assets. To keep several attachments, read the cell, add the
new object from hb_upload_file() and write it back with
hb_update_rows().
Invisibly returns the client.
Other files:
hb_delete_asset(),
hb_download_file(),
hb_upload_file()
## Not run: client <- hb_client() hb_attach_file(client, "Samples", "abc", "Reports", "report.pdf") ## End(Not run)## Not run: client <- hb_client() hb_attach_file(client, "Samples", "abc", "Reports", "report.pdf") ## End(Not run)
Exchanges the client's credentials for a token, which is the cheapest way to find out whether they work. For an API-token client this fetches a base token, and so also confirms the token is valid for that base; for a username/password client it fetches an account token and then drops any cached base token, so that the next base call fetches a new one.
hb_check_credentials(client, ...)hb_check_credentials(client, ...)
client |
A |
... |
These dots are for future extensions and must be empty. |
Unlike hb_ping(), which only proves the server is up, this proves the
credentials are usable.
The client, invisibly. Errors with a harbour_error_auth
condition if the credentials are rejected.
Other client:
hb_client(),
hb_ping(),
hb_server_info(),
is_harbour_client()
## Not run: client <- hb_client() hb_check_credentials(client) ## End(Not run)## Not run: client <- hb_client() hb_check_credentials(client) ## End(Not run)
Builds a harbour_client object that holds the server URL, the user's
credentials and a lazily-fetched, transparently-refreshed base token.
The client is environment-backed, so internal token refreshes mutate
cached state in place without reassigning your variable.
hb_client( server = Sys.getenv("SEATABLE_SERVER"), api_token = Sys.getenv("SEATABLE_API_TOKEN"), ..., username = NULL, password = NULL, base_uuid = NULL, workspace_id = NULL, base_name = NULL, timeout = 30 ) ## S3 method for class 'harbour_client' print(x, ...) ## S3 method for class 'harbour_client' format(x, ...)hb_client( server = Sys.getenv("SEATABLE_SERVER"), api_token = Sys.getenv("SEATABLE_API_TOKEN"), ..., username = NULL, password = NULL, base_uuid = NULL, workspace_id = NULL, base_name = NULL, timeout = 30 ) ## S3 method for class 'harbour_client' print(x, ...) ## S3 method for class 'harbour_client' format(x, ...)
server |
URL of the SeaTable server, e.g.
|
api_token |
Long-lived per-base API token. Defaults to the
|
... |
These dots are for future extensions and must be empty. |
username, password
|
Account credentials. Used to acquire an account
token. Mutually exclusive with |
base_uuid |
Optional base UUID hint; usually discovered from the base-token exchange. |
workspace_id, base_name
|
Which base to work on. Required for a
|
timeout |
Per-request timeout in seconds, a positive number of
at most 2147483, or |
x |
A |
SeaTable uses a three-token model. hb_client() accepts either an
API token (per-base, long-lived, generated in the SeaTable UI) or
username + password (which yields an account token). In-base calls
transparently exchange these for a short-lived base token.
Defaults for server and api_token are read from the environment
variables SEATABLE_SERVER and SEATABLE_API_TOKEN.
A harbour_client object.
print() returns x, invisibly.
format() returns a character vector, one element per field.
Other client:
hb_check_credentials(),
hb_ping(),
hb_server_info(),
is_harbour_client()
# creating a client does not contact the server client <- hb_client( server = "https://seatable.example.org", api_token = "your-api-token" ) client # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client( server = Sys.getenv("SEATABLE_SERVER"), api_token = Sys.getenv("SEATABLE_API_TOKEN") ) print(client) ## End(Not run)# creating a client does not contact the server client <- hb_client( server = "https://seatable.example.org", api_token = "your-api-token" ) client # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client( server = Sys.getenv("SEATABLE_SERVER"), api_token = Sys.getenv("SEATABLE_API_TOKEN") ) print(client) ## End(Not run)
The single source of truth for the coercion layer: one row per type name, giving the R type harbouR produces when reading, whether that R type is a list-column, and whether harbouR leaves the column out of writes. The coercion functions and the column-types vignette are both derived from this table, so they cannot drift apart.
hb_column_types()hb_column_types()
percent, dollar and euro are number formats rather than column
types: SeaTable reports such a column as type "number", with the
format in its data$format. They are listed so that tables carrying
them as a type still coerce.
A date column reads as POSIXct in UTC. When the column's format has
no time part, the cell holds a calendar date, and harbouR reads the date
SeaTable shows as midnight UTC, whatever UTC offset the server sends
with it, so as.Date() gives that date. A date-time read from a server
is an instant and is converted to UTC; a date-time stored without an
offset, as in a .dtable file, is read as UTC. A column that reports
no format is read as a date-time.
Written to a date-only column, a Date is sent as itself and a
date-time as the date it shows in its own time zone, except one at
exactly midnight UTC, which keeps its UTC date: a cell read and written
back keeps its day. A date-time column is sent the instant, in UTC.
A tibble with one row per type and columns:
seatablechr. The type name as SeaTable reports it, or one of the number formats above.
rchr. The R type harbouR reads it as.
is_listlgl. Whether the result is a list-column.
read_onlylgl. Whether harbouR leaves the column out of
writes. Most of these are computed or maintained by SeaTable; a
digital-sign cell is left out because a signature should come
from the signer.
noteschr. Anything worth knowing.
Other metadata:
as_tibble.harbour_metadata(),
hb_list_collaborators(),
hb_list_tables(),
hb_metadata(),
is_harbour_metadata(),
print.harbour_metadata(),
summary.harbour_metadata()
hb_column_types() # the types harbouR does not write subset(hb_column_types(), read_only)hb_column_types() # the types harbouR does not write subset(hb_column_types(), read_only)
Create a table
hb_create_table(client, table, ..., columns = list())hb_create_table(client, table, ..., columns = list())
client |
A |
table |
Name of the new table. |
... |
These dots are for future extensions and must be empty. |
columns |
A list of column specifications: each element a named list
with at least |
Invisibly returns the client.
Other tables:
hb_delete_table(),
hb_duplicate_table(),
hb_rename_table()
## Not run: client <- hb_client() hb_create_table(client, "NewTable", columns = list(list(name = "Name", type = "text"))) ## End(Not run)## Not run: client <- hb_client() hb_create_table(client, "NewTable", columns = list(list(name = "Name", type = "text"))) ## End(Not run)
Create a view
hb_create_view(client, table, view, ..., settings = list())hb_create_view(client, table, view, ..., settings = list())
client |
A |
table |
Table name. |
view |
New view name. |
... |
These dots are for future extensions and must be empty. |
settings |
Optional named list of further fields for the new view,
such as |
Invisibly returns the client.
Other views:
hb_delete_view(),
hb_get_view(),
hb_list_views(),
hb_update_view()
## Not run: client <- hb_client() hb_create_view(client, "Samples", "Active") ## End(Not run)## Not run: client <- hb_client() hb_create_view(client, "Samples", "Active") ## End(Not run)
Removes a file or image from the base's assets. Like the other file endpoints this authenticates with the API token. Cells that still point at the asset are not changed.
hb_delete_asset(client, url, ...)hb_delete_asset(client, url, ...)
client |
A |
url |
Asset URL (as returned by SeaTable in a file/image cell). |
... |
These dots are for future extensions and must be empty. |
url is the URL from a file or image cell, absolute or relative to the
server, or a path below the base's asset root such as
/files/2026-07/report.pdf. The endpoint acts on the client's base
whatever the URL names, so a URL on another server, or an asset URL of
another base, raises a harbour_error_bad_argument condition rather
than deleting this base's file at the same path.
Invisibly returns the client.
Other files:
hb_attach_file(),
hb_download_file(),
hb_upload_file()
## Not run: client <- hb_client() # A path below the asset root, or the URL from a file or image cell hb_delete_asset(client, "/files/2026-07/report.pdf") ## End(Not run)## Not run: client <- hb_client() # A path below the asset root, or the URL from a file or image cell hb_delete_asset(client, "/files/2026-07/report.pdf") ## End(Not run)
Delete a column
hb_delete_column(client, table, name, ...)hb_delete_column(client, table, name, ...)
client |
A |
table |
Table name. |
name |
Column name. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other columns:
hb_add_column(),
hb_add_columns(),
hb_add_select_option(),
hb_delete_select_option(),
hb_list_columns(),
hb_update_column(),
hb_update_select_option()
## Not run: client <- hb_client() hb_delete_column(client, "Samples", "Old") ## End(Not run)## Not run: client <- hb_client() hb_delete_column(client, "Samples", "Old") ## End(Not run)
Delete rows
hb_delete_rows(client, table, row_ids, ..., chunk_size = 1000L)hb_delete_rows(client, table, row_ids, ..., chunk_size = 1000L)
client |
A |
table |
Table name. |
row_ids |
A character vector of row IDs to delete. |
... |
These dots are for future extensions and must be empty. |
chunk_size |
Rows per request. SeaTable caps batch writes at 1000 and harbouR clamps it, warning if you asked for more. |
Invisibly, a one-row tibble with columns table (chr),
n_rows (int) and n_requests (int).
Other rows:
hb_append_rows(),
hb_get_row(),
hb_lock_rows(),
hb_query(),
hb_read_table(),
hb_unlock_rows(),
hb_update_rows()
## Not run: client <- hb_client() hb_delete_rows(client, "Samples", c("abc", "def")) ## End(Not run)## Not run: client <- hb_client() hb_delete_rows(client, "Samples", c("abc", "def")) ## End(Not run)
Delete a single-select option
hb_delete_select_option(client, table, name, option, ...)hb_delete_select_option(client, table, name, option, ...)
client |
A |
table |
Table name. |
name |
Column name. |
option |
Name of the option to delete. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other columns:
hb_add_column(),
hb_add_columns(),
hb_add_select_option(),
hb_delete_column(),
hb_list_columns(),
hb_update_column(),
hb_update_select_option()
## Not run: client <- hb_client() hb_delete_select_option(client, "Samples", "Status", "Old") ## End(Not run)## Not run: client <- hb_client() hb_delete_select_option(client, "Samples", "Status", "Old") ## End(Not run)
Delete a table
hb_delete_table(client, table, ...)hb_delete_table(client, table, ...)
client |
A |
table |
Name of the table to delete. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other tables:
hb_create_table(),
hb_duplicate_table(),
hb_rename_table()
## Not run: client <- hb_client() hb_delete_table(client, "DropMe") ## End(Not run)## Not run: client <- hb_client() hb_delete_table(client, "DropMe") ## End(Not run)
SeaTable's API addresses one view by its name in the URL, and its server reads a slash in that name as a path separator and a name of one or two dots as a folder. Such a view cannot be deleted through the API, and harbouR says so before sending anything: rename it in SeaTable first.
hb_delete_view(client, table, view, ...)hb_delete_view(client, table, view, ...)
client |
A |
table |
Table name. |
view |
View name. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other views:
hb_create_view(),
hb_get_view(),
hb_list_views(),
hb_update_view()
## Not run: client <- hb_client() hb_delete_view(client, "Samples", "Old") ## End(Not run)## Not run: client <- hb_client() hb_delete_view(client, "Samples", "Old") ## End(Not run)
A URL in a file or image cell is not directly downloadable: the asset
sits behind SeaTable's login. harbouR recognises such a URL by its
path, /workspace/<id>/asset/<base uuid>/..., whether it is absolute
or relative to the server, and exchanges it, with the client's API
token, for a short-lived download link. The URL must name the client's
server - the host is compared ignoring case, the scheme and a default
port - and the client's base: an asset of another server or another
base raises a harbour_error_bad_argument condition instead of being
fetched. A URL that is not an asset URL is fetched as it is.
hb_download_file(client, url, dest, ..., overwrite = FALSE)hb_download_file(client, url, dest, ..., overwrite = FALSE)
client |
A |
url |
Asset URL (as returned by SeaTable in a file/image cell). |
dest |
Destination path. Parent directories are created if needed. |
... |
These dots are for future extensions and must be empty. |
overwrite |
Refuse to clobber an existing file unless |
Should SeaTable answer an asset download with its login page, the
download fails with a harbour_error_http condition rather than saving
the page in place of the file.
The file is written to a temporary name beside dest and moved into
place only once complete, so a failed download never leaves a partial
file and never destroys the file overwrite = TRUE would replace.
Invisibly returns dest.
Other files:
hb_attach_file(),
hb_delete_asset(),
hb_upload_file()
## Not run: client <- hb_client() hb_download_file(client, "https://...", tempfile()) ## End(Not run)## Not run: client <- hb_client() hb_download_file(client, "https://...", tempfile()) ## End(Not run)
.dtable base from data framesCreates a harbour_dtable from scratch, so a set of R data frames can
be written out as a SeaTable base and imported.
hb_dtable(..., base_name = "harbouR base", collaborators = NULL)hb_dtable(..., base_name = "harbouR base", collaborators = NULL)
... |
Named data frames, one per table. |
base_name |
Name recorded for the base. |
collaborators |
Optional list of collaborator records. |
Column types are inferred: character becomes text, numeric
number, logical checkbox, Date and POSIXct date, factor
single-select with its levels as options, and a list-column of
character vectors multiple-select with the values it uses as options.
A list-column holding objects - file, image or location cells read from
a live base - is flattened to text: a new base has none of the assets
those cells point at.
A Date column, or a date-time column whose every value is midnight
UTC - which is how hb_read_table() reads a date-only column - becomes
a date column showing the date alone. Other date-times are written with
their UTC offset, so the server stores the instant whatever zone it
runs in.
A column named _id, such as the one hb_read_table() adds, is
dropped: SeaTable keeps that name for the row identifier, and the new
base has identifiers of its own. One that holds anything but SeaTable
row ids is dropped with a harbour_warning_id_column warning.
New row ids, table ids, column keys and select-option ids are drawn
from the session's random number generator, so building a base
advances .Random.seed: a random draw made after hb_dtable() differs
from the same draw made without it. Set the seed after building the
base when an analysis needs its random numbers not to depend on it.
A harbour_dtable, with the components hb_read_dtable()
describes, holding one table per data frame.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
base <- hb_dtable( Samples = data.frame(Name = c("a", "b"), Value = c(1.5, 2.5)), base_name = "My base" ) base hb_read_table(base, "Samples")base <- hb_dtable( Samples = data.frame(Name = c("a", "b"), Value = c(1.5, 2.5)), base_name = "My base" ) base hb_read_table(base, "Samples")
Duplicate a table
hb_duplicate_table(client, table, ..., duplicate_records = TRUE)hb_duplicate_table(client, table, ..., duplicate_records = TRUE)
client |
A |
table |
Source table name. |
... |
These dots are for future extensions and must be empty. |
duplicate_records |
Copy the rows as well as the structure.
Default |
Invisibly returns the client.
SeaTable names the copy after the original with (copy) appended, with
no space - a copy of Samples is Samples(copy) - and offers no way to
set the name in the same request. Follow with hb_rename_table() if you
need a particular name.
Other tables:
hb_create_table(),
hb_delete_table(),
hb_rename_table()
## Not run: client <- hb_client() hb_duplicate_table(client, "Samples") hb_rename_table(client, "Samples(copy)", "Samples_backup") ## End(Not run)## Not run: client <- hb_client() hb_duplicate_table(client, "Samples") hb_rename_table(client, "Samples(copy)", "Samples_backup") ## End(Not run)
A small, hand-crafted SeaTable base used to power offline examples and tests. The shape of the returned object matches what the SeaTable metadata endpoint would yield.
hb_example_metadata()hb_example_metadata()
The base is defined once, in inst/extdata/example_metadata.json, and
parsed on each call. Keeping it in a data file rather than in R source
means the demo base is also readable from outside R, and there is only
one definition to keep in step with the coercion layer.
A harbour_metadata object describing a tiny base with two
tables: Samples and Patients.
Other example data:
hb_example_rows()
meta <- hb_example_metadata() tibble::as_tibble(meta)meta <- hb_example_metadata() tibble::as_tibble(meta)
Returns a tibble of example rows for one of the tables provided by
hb_example_metadata(), so tests and the column-types vignette can
demonstrate the coercion layer without a SeaTable server.
hb_example_rows(table = c("Samples", "Patients"))hb_example_rows(table = c("Samples", "Patients"))
table |
One of |
Between them the two tables cover the common column types - text,
number, single-select, multiple-select, date, collaborator, file and
checkbox - so the rows include list-columns and date-times. For the
fuller set, read the bundled .dtable file with hb_read_dtable(): it
carries a column of nearly every type, at
system.file("extdata", "example.dtable", package = "harbouR").
A tibble with one row per example record: a column for each
column of table in hb_example_metadata(), and the row id _id.
Multiple-select, collaborator and file columns are list-columns, and
dates are date-times in UTC.
Other example data:
hb_example_metadata()
hb_example_rows("Samples")hb_example_rows("Samples")
Get a single row by ID
hb_get_row(client, table, row_id, ...)hb_get_row(client, table, row_id, ...)
client |
A |
table |
Table name. |
row_id |
The SeaTable row identifier. |
... |
These dots are for future extensions and must be empty. |
A one-row tibble with one column per SeaTable column, plus
_id (chr). An unknown row_id is an error - a
harbour_error_not_found condition - not an empty result, because
asking for a specific row that does not exist is a mistake worth
surfacing.
Other rows:
hb_append_rows(),
hb_delete_rows(),
hb_lock_rows(),
hb_query(),
hb_read_table(),
hb_unlock_rows(),
hb_update_rows()
## Not run: client <- hb_client() hb_get_row(client, "Samples", "abc123") ## End(Not run)## Not run: client <- hb_client() hb_get_row(client, "Samples", "abc123") ## End(Not run)
SeaTable's API addresses one view by its name in the URL, and its server reads a slash in that name as a path separator and a name of one or two dots as a folder. Such a view is looked up in the table's list of views instead.
hb_get_view(client, table, view, ...)hb_get_view(client, table, view, ...)
client |
A |
table |
Table name. |
view |
View name. |
... |
These dots are for future extensions and must be empty. |
A one-row tibble with columns name (chr), type (chr),
is_default (lgl), filters (list), sorts (list) and
hidden_columns (list of chr).
Other views:
hb_create_view(),
hb_delete_view(),
hb_list_views(),
hb_update_view()
## Not run: client <- hb_client() hb_get_view(client, "Samples", "Default") ## End(Not run)## Not run: client <- hb_client() hb_get_view(client, "Samples", "Default") ## End(Not run)
List collaborators of the active base
hb_list_collaborators(client, ...)hb_list_collaborators(client, ...)
client |
A |
... |
These dots are for future extensions and must be empty. |
A tibble with columns email (chr), name (chr) and
contact_email (chr). Zero rows if none are reported.
Other metadata:
as_tibble.harbour_metadata(),
hb_column_types(),
hb_list_tables(),
hb_metadata(),
is_harbour_metadata(),
print.harbour_metadata(),
summary.harbour_metadata()
## Not run: client <- hb_client() hb_list_collaborators(client) ## End(Not run)## Not run: client <- hb_client() hb_list_collaborators(client) ## End(Not run)
List columns of a table
hb_list_columns(x, table, ...) ## S3 method for class 'harbour_client' hb_list_columns(x, table, ..., refresh = FALSE) ## S3 method for class 'harbour_dtable' hb_list_columns(x, table, ...) ## Default S3 method: hb_list_columns(x, table, ...)hb_list_columns(x, table, ...) ## S3 method for class 'harbour_client' hb_list_columns(x, table, ..., refresh = FALSE) ## S3 method for class 'harbour_dtable' hb_list_columns(x, table, ...) ## Default S3 method: hb_list_columns(x, table, ...)
x |
A |
table |
Table name. |
... |
These dots are for future extensions and must be empty. |
refresh |
Logical. Ask the server rather than reusing the cached
base metadata. Default |
A tibble with one row per column and columns name (chr),
type (chr), key (chr), editable (lgl) and data (list).
editable says whether harbouR writes the column: it is FALSE for
the types hb_column_types() marks read_only. SeaTable's own
editable flag is not used, since it is set for formula columns too.
The
data list-column holds the column's type-specific configuration -
for a select column, its options.
Other columns:
hb_add_column(),
hb_add_columns(),
hb_add_select_option(),
hb_delete_column(),
hb_delete_select_option(),
hb_update_column(),
hb_update_select_option()
# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") hb_list_columns(hb_read_dtable(path), "Samples") # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_list_columns(client, "Samples") ## End(Not run)# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") hb_list_columns(hb_read_dtable(path), "Samples") # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_list_columns(client, "Samples") ## End(Not run)
List the tables in a base
hb_list_tables(x, ...) ## S3 method for class 'harbour_dtable' hb_list_tables(x, ...) ## Default S3 method: hb_list_tables(x, ...) ## S3 method for class 'harbour_client' hb_list_tables(x, ..., refresh = FALSE)hb_list_tables(x, ...) ## S3 method for class 'harbour_dtable' hb_list_tables(x, ...) ## Default S3 method: hb_list_tables(x, ...) ## S3 method for class 'harbour_client' hb_list_tables(x, ..., refresh = FALSE)
x |
A |
... |
These dots are for future extensions and must be empty. |
refresh |
Logical; refetch metadata even if cached. Default |
A tibble with one row per table and columns name (chr),
n_columns (int) and n_views (int).
The server path stops there: the metadata endpoint carries no row
payloads, so there is no row count to report - use hb_read_table()
if you need one. The .dtable path additionally returns n_rows
(int), because in a file the rows are right there.
Other metadata:
as_tibble.harbour_metadata(),
hb_column_types(),
hb_list_collaborators(),
hb_metadata(),
is_harbour_metadata(),
print.harbour_metadata(),
summary.harbour_metadata()
# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") hb_list_tables(hb_read_dtable(path)) # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_list_tables(client) ## End(Not run)# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") hb_list_tables(hb_read_dtable(path)) # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_list_tables(client) ## End(Not run)
List views of a table
hb_list_views(x, table, ...) ## S3 method for class 'harbour_dtable' hb_list_views(x, table, ...) ## Default S3 method: hb_list_views(x, table, ...) ## S3 method for class 'harbour_client' hb_list_views(x, table, ..., refresh = FALSE)hb_list_views(x, table, ...) ## S3 method for class 'harbour_dtable' hb_list_views(x, table, ...) ## Default S3 method: hb_list_views(x, table, ...) ## S3 method for class 'harbour_client' hb_list_views(x, table, ..., refresh = FALSE)
x |
A |
table |
Table name. |
... |
These dots are for future extensions and must be empty. |
refresh |
Logical. Ask the server rather than reusing the cached
base metadata. Default |
A tibble with columns name (chr), type (chr) and is_default
(lgl). Zero rows if no views exist.
Other views:
hb_create_view(),
hb_delete_view(),
hb_get_view(),
hb_update_view()
# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") hb_list_views(hb_read_dtable(path), "Samples") # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_list_views(client, "Samples") ## End(Not run)# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") hb_list_views(hb_read_dtable(path), "Samples") # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_list_views(client, "Samples") ## End(Not run)
Lock rows
hb_lock_rows(client, table, row_ids, ...)hb_lock_rows(client, table, row_ids, ...)
client |
A |
table |
Table name. |
row_ids |
A character vector of row IDs to lock. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other rows:
hb_append_rows(),
hb_delete_rows(),
hb_get_row(),
hb_query(),
hb_read_table(),
hb_unlock_rows(),
hb_update_rows()
## Not run: client <- hb_client() hb_lock_rows(client, "Samples", "abc") ## End(Not run)## Not run: client <- hb_client() hb_lock_rows(client, "Samples", "abc") ## End(Not run)
Retrieves the structural metadata for a SeaTable base - the list of tables, their columns (with SeaTable types) and views. The result is cached on the client.
hb_metadata(client, ...)hb_metadata(client, ...)
client |
A |
... |
These dots are for future extensions and must be empty. |
A harbour_metadata object - a list with components
base_name (chr), tables (list), version (chr).
Other metadata:
as_tibble.harbour_metadata(),
hb_column_types(),
hb_list_collaborators(),
hb_list_tables(),
is_harbour_metadata(),
print.harbour_metadata(),
summary.harbour_metadata()
## Not run: client <- hb_client() meta <- hb_metadata(client) tibble::as_tibble(meta) ## End(Not run)## Not run: client <- hb_client() meta <- hb_metadata(client) tibble::as_tibble(meta) ## End(Not run)
Issues a lightweight, unauthenticated request against the server's ping
endpoint. This tests connectivity only - use hb_check_credentials()
to test whether the client's credentials are accepted.
hb_ping(client, ...)hb_ping(client, ...)
client |
A |
... |
These dots are for future extensions and must be empty. |
Returns the client invisibly, so it composes:
client |> hb_ping() |> hb_read_table("Samples").
The client, invisibly. Errors with a harbour_error_http
condition if the server cannot be reached, and with the class of the
answer - harbour_error_not_found for a 404, say - if it answers
with an error.
Other client:
hb_check_credentials(),
hb_client(),
hb_server_info(),
is_harbour_client()
## Not run: client <- hb_client() hb_ping(client) ## End(Not run)## Not run: client <- hb_client() hb_ping(client) ## End(Not run)
Run a SeaTable SQL query
hb_query(client, sql, ..., parameters = NULL, convert_keys = TRUE)hb_query(client, sql, ..., parameters = NULL, convert_keys = TRUE)
client |
A |
sql |
SeaTable SQL query string. SeaTable applies an implicit
|
... |
These dots are for future extensions and must be empty. |
parameters |
Optional list of values for |
convert_keys |
Return column names rather than column keys.
Default |
A tibble, typed from the result schema SeaTable reports
alongside the rows, so the same table read via hb_read_table() and
via hb_query() yields the same column types. Always a tibble, even
when the query returns no rows.
Other rows:
hb_append_rows(),
hb_delete_rows(),
hb_get_row(),
hb_lock_rows(),
hb_read_table(),
hb_unlock_rows(),
hb_update_rows()
## Not run: client <- hb_client() hb_query(client, "select * from Samples limit 5") ## End(Not run)## Not run: client <- hb_client() hb_query(client, "select * from Samples limit 5") ## End(Not run)
Builds a fresh harbour_dtable from CSV files, one table per file.
This is not the inverse of hb_write_csv(): it produces a new base
with new identifiers, and only text, number and checkbox columns.
Nothing that a CSV cannot carry is recovered.
hb_read_csv(files, ..., base_name = "harbouR base")hb_read_csv(files, ..., base_name = "harbouR base")
files |
Paths to |
... |
These dots are for future extensions and must be empty. |
base_name |
Name recorded for the new base. |
Columns are typed the way utils::read.csv() types them, and quoting a
value does not change that:
A column of numbers becomes number, and one holding only T, F,
TRUE or FALSE becomes checkbox.
A value written NA is read as missing.
Dates and date-times arrive as text.
Some exceptions avoid losing data. A column holding an integer with a
leading zero, such as "0001", a value with a leading plus, such as
the telephone number "+4917612345678", or an integer of more than 15
digits stays text, rather than losing the zeros, the plus or digits,
and so does one holding a code such as "12E", which
utils::read.csv() reads as 12 in R before 4.4.1. A column with no
values at all is text, not a checkbox column that would read FALSE
in every row.
The files must be UTF-8, with or without a byte-order mark. A file in
another encoding is refused, naming the first line that is not valid
UTF-8. In a multibyte session that is not UTF-8, such as Shift-JIS or
GBK, the text goes through that session's encoding, so characters it
lacks are lost; read such files in a UTF-8 session. A column named
_id, such as the one hb_write_csv() writes,
is dropped: SeaTable keeps that name for the row identifier, and the new
base has identifiers of its own. One that holds anything but SeaTable
row ids, such as a database's keys, is dropped with a warning.
A harbour_dtable, with the components hb_read_dtable()
describes, holding one table per file.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
csv <- tempfile(fileext = ".csv") utils::write.csv(data.frame(x = 1:2, y = c("a", "b")), csv, row.names = FALSE) hb_read_csv(c(Measurements = csv))csv <- tempfile(fileext = ".csv") utils::write.csv(data.frame(x = 1:2, y = c("a", "b")), csv, row.names = FALSE) hb_read_csv(c(Measurements = csv))
.dtable fileOpens a .dtable export and returns a harbour_dtable object. The
same verbs that work against a live base work against it -
hb_list_tables(), hb_read_table(), hb_list_columns() - so an
analysis can be written once and run either way.
hb_read_dtable(path, ..., assets = c("none", "extract"), assets_dir = NULL)hb_read_dtable(path, ..., assets = c("none", "extract"), assets_dir = NULL)
path |
Path to a |
... |
These dots are for future extensions and must be empty. |
assets |
Whether to extract the bundled |
assets_dir |
Where to extract assets to. Defaults to a session
temporary directory. A folder that already holds an |
A .dtable is a ZIP archive containing content.json, the complete
base, and optionally an asset/ tree of uploaded files and images.
The parsed JSON is kept verbatim. Real exports carry fields no
client would think to model - one column in the reference file holds a
serialised React element - and future SeaTable releases will add more.
Keeping the tree untouched is what makes hb_write_dtable() lossless;
rebuilding it from a typed intermediate would quietly drop whatever
harbouR did not know about.
A harbour_dtable: a list with components content (the
parsed tree), path, assets (the archive's own listing of its
asset/ tree, as zip::zip_list() gives it: one row per entry,
folders included), assets_dir and base_name. Note that names()
on a harbour_dtable gives its table names, not these components -
reach them with $ or unclass().
harbouR.dtable_tz: the time zone of the SeaTable server a file
comes from, such as "Europe/Berlin". A server stores a date-time as
the time it shows, with no offset, and its export keeps it so; such a
value is read in this zone. Unset, it is read as UTC, with a warning
once a session. Date-only cells, and values that carry an offset,
need no zone.
harbouR.max_dtable_bytes: how large content.json, plus the
assets when they are extracted, may be once unpacked. Default 4 GiB.
A larger file is refused before anything is read, since a small
archive can unpack to enough to fill memory or disk.
hb_write_dtable(), hb_dtable()
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
path <- system.file("extdata", "example.dtable", package = "harbouR") base <- hb_read_dtable(path) base hb_list_tables(base) hb_read_table(base, "Samples")path <- system.file("extdata", "example.dtable", package = "harbouR") base <- hb_read_dtable(path) base hb_list_tables(base) hb_read_table(base, "Samples")
Reads all rows from table (optionally filtered by view) and returns
them as a typed tibble. Pagination is handled internally; the returned
tibble always has the table's columns in declared order plus an _id
column.
hb_read_table(x, table, ...) ## S3 method for class 'harbour_dtable' hb_read_table(x, table, ..., view = NULL, n_max = Inf, option_labels = TRUE) ## Default S3 method: hb_read_table(x, table, ...) ## S3 method for class 'harbour_client' hb_read_table(x, table, ..., view = NULL, page_size = 1000L, n_max = Inf)hb_read_table(x, table, ...) ## S3 method for class 'harbour_dtable' hb_read_table(x, table, ..., view = NULL, n_max = Inf, option_labels = TRUE) ## Default S3 method: hb_read_table(x, table, ...) ## S3 method for class 'harbour_client' hb_read_table(x, table, ..., view = NULL, page_size = 1000L, n_max = Inf)
x |
A |
table |
Name of the table. |
... |
These dots are for future extensions and must be empty. |
view |
Optional view name. A server returns only the columns a
view shows, so a read through a view gives |
n_max |
Maximum number of rows to return. |
option_labels |
Translate select-option ids to their display
names. On disk a select cell holds an option id; over the API it
holds the name, so this is what makes a local read and a server read
of the same column agree. Set |
page_size |
Rows fetched per request. SeaTable caps this at 1000 and harbouR clamps it, warning if you asked for more. |
A tibble with one row per SeaTable row and one column per
SeaTable column, plus _id (chr). A 0-row tibble is returned for an
empty table.
.dtable fileOn a harbour_dtable, view restricts the rows only to the row ids
the file records for that view, kept in table order. The view's filters
and sorts are not applied. A view that records no rows returns the
whole table, with a warning of class harbour_warning_view_filters
when the view has filters that were therefore not applied.
Other rows:
hb_append_rows(),
hb_delete_rows(),
hb_get_row(),
hb_lock_rows(),
hb_query(),
hb_unlock_rows(),
hb_update_rows()
# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") base <- hb_read_dtable(path) hb_read_table(base, "Samples") hb_read_table(base, "Samples", n_max = 1) # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_read_table(client, "Samples") # just the first 10 rows hb_read_table(client, "Samples", n_max = 10) ## End(Not run)# a .dtable file needs no server path <- system.file("extdata", "example.dtable", package = "harbouR") base <- hb_read_dtable(path) hb_read_table(base, "Samples") hb_read_table(base, "Samples", n_max = 1) # a live base needs a SeaTable server and an API token ## Not run: client <- hb_client() hb_read_table(client, "Samples") # just the first 10 rows hb_read_table(client, "Samples", n_max = 10) ## End(Not run)
One table per worksheet. Like hb_read_csv(), this produces a new
base rather than restoring one.
hb_read_xlsx(path, ..., sheets = NULL, base_name = "harbouR base")hb_read_xlsx(path, ..., sheets = NULL, base_name = "harbouR base")
path |
Path to an |
... |
These dots are for future extensions and must be empty. |
sheets |
Worksheet names to read. Default: all of them. |
base_name |
Name recorded for the new base. |
A column's type follows its cells, judged over every row of the sheet.
A column with no values at all is text. The spaces around a text value
are kept. A column named _id, such as
the one hb_write_xlsx() writes, is dropped, with a warning when it
holds anything but SeaTable row ids.
A harbour_dtable, with the components hb_read_dtable()
describes, holding one table per sheet read.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
path <- tempfile(fileext = ".xlsx") writexl::write_xlsx(list(Samples = data.frame(x = 1:2)), path) hb_read_xlsx(path)path <- tempfile(fileext = ".xlsx") writexl::write_xlsx(list(Samples = data.frame(x = 1:2)), path) hb_read_xlsx(path)
Rename a table
hb_rename_table(client, table, new_name, ...)hb_rename_table(client, table, new_name, ...)
client |
A |
table |
Current table name. |
new_name |
New table name. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other tables:
hb_create_table(),
hb_delete_table(),
hb_duplicate_table()
## Not run: client <- hb_client() hb_rename_table(client, "Old", "New") ## End(Not run)## Not run: client <- hb_client() hb_rename_table(client, "Old", "New") ## End(Not run)
A Shiny app for working with a SeaTable base without writing code:
open a local .dtable export or connect to a server, browse the
tables, read the schema, run SQL, and download the result as
.dtable, Excel or CSV.
hb_run_explorer(x = NULL, ..., host = "127.0.0.1", port = NULL)hb_run_explorer(x = NULL, ..., host = "127.0.0.1", port = NULL)
x |
Optional |
... |
Passed to |
host |
Host to bind. Default |
port |
Port. Default |
Pass a connected hb_client() or a base read with hb_read_dtable()
to start there. With no argument the app opens on its source panel,
which offers a bundled example base that needs no credentials and no
network.
The UI packages (shiny, bslib, reactable) are in Suggests, so
the client itself stays headless. A missing one, or a bslib older
than 0.6.0, produces a single informative error rather than a stack
trace. The Excel download also needs writexl; without it the app
says so when you ask for one.
Shiny refuses uploads over 5 MB by default, and a .dtable with
attachments is often larger, so while the app runs it accepts files up
to 1 GB. To choose another limit, set the shiny.maxRequestSize
option, in bytes, before calling hb_run_explorer(); a value you have
set is left as it is.
Invisible NULL; launches a Shiny application.
# the bundled example base, no credentials needed hb_run_explorer() # or start from a file, with its attachments, so that a .dtable # download keeps them path <- system.file("extdata", "example.dtable", package = "harbouR") hb_run_explorer(hb_read_dtable(path, assets = "extract"))# the bundled example base, no credentials needed hb_run_explorer() # or start from a file, with its attachments, so that a .dtable # download keeps them path <- system.file("extdata", "example.dtable", package = "harbouR") hb_run_explorer(hb_read_dtable(path, assets = "extract"))
Returns the SeaTable server's reported version and basic info. This endpoint is unauthenticated.
hb_server_info(client, ...)hb_server_info(client, ...)
client |
A |
... |
These dots are for future extensions and must be empty. |
A one-row tibble with columns server (chr), version (chr) and
edition (chr) where reported.
Other client:
hb_check_credentials(),
hb_client(),
hb_ping(),
is_harbour_client()
## Not run: client <- hb_client() hb_server_info(client) ## End(Not run)## Not run: client <- hb_client() hb_server_info(client) ## End(Not run)
Unlock rows
hb_unlock_rows(client, table, row_ids, ...)hb_unlock_rows(client, table, row_ids, ...)
client |
A |
table |
Table name. |
row_ids |
A character vector of row IDs to unlock. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other rows:
hb_append_rows(),
hb_delete_rows(),
hb_get_row(),
hb_lock_rows(),
hb_query(),
hb_read_table(),
hb_update_rows()
## Not run: client <- hb_client() hb_unlock_rows(client, "Samples", "abc") ## End(Not run)## Not run: client <- hb_client() hb_unlock_rows(client, "Samples", "abc") ## End(Not run)
Update a column
hb_update_column( client, table, name, ..., new_name = NULL, new_type = NULL, column_data = NULL )hb_update_column( client, table, name, ..., new_name = NULL, new_type = NULL, column_data = NULL )
client |
A |
table |
Table name. |
name |
Column name. |
... |
These dots are for future extensions and must be empty. |
new_name |
Optional new column name. Sends |
new_type |
Optional new SeaTable column type. Sends |
column_data |
Optional list of column options, sent with the type
change. Given without |
Invisibly returns the client.
Other columns:
hb_add_column(),
hb_add_columns(),
hb_add_select_option(),
hb_delete_column(),
hb_delete_select_option(),
hb_list_columns(),
hb_update_select_option()
## Not run: client <- hb_client() hb_update_column(client, "Samples", "Notes", new_name = "Comments") ## End(Not run)## Not run: client <- hb_client() hb_update_column(client, "Samples", "Notes", new_name = "Comments") ## End(Not run)
Every column of data that the table can store is written, so an NA
clears its cell. The exception is a tibble read through a view with
hb_read_table(): the columns the view hides come back as NA, and a
cell of theirs is left out of the write unless it has been filled in,
so writing such a tibble back does not erase them.
hb_update_rows( client, table, data, ..., row_id_col = "_id", chunk_size = 1000L )hb_update_rows( client, table, data, ..., row_id_col = "_id", chunk_size = 1000L )
client |
A |
table |
Table name. |
data |
A tibble or data frame whose columns match the table schema. |
... |
These dots are for future extensions and must be empty. |
row_id_col |
Name of the column in |
chunk_size |
Rows per request. SeaTable caps batch writes at 1000 and harbouR clamps it, warning if you asked for more. |
Invisibly, a one-row tibble with columns table (chr),
n_rows (int) and n_requests (int).
Other rows:
hb_append_rows(),
hb_delete_rows(),
hb_get_row(),
hb_lock_rows(),
hb_query(),
hb_read_table(),
hb_unlock_rows()
## Not run: client <- hb_client() hb_update_rows( client, "Samples", tibble::tibble(`_id` = "abc", Name = "renamed") ) ## End(Not run)## Not run: client <- hb_client() hb_update_rows( client, "Samples", tibble::tibble(`_id` = "abc", Name = "renamed") ) ## End(Not run)
Update a single-select option
hb_update_select_option(client, table, name, option, new_option, ...)hb_update_select_option(client, table, name, option, new_option, ...)
client |
A |
table |
Table name. |
name |
Column name. |
option |
Name of the option to rename. |
new_option |
New option name. |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other columns:
hb_add_column(),
hb_add_columns(),
hb_add_select_option(),
hb_delete_column(),
hb_delete_select_option(),
hb_list_columns(),
hb_update_column()
## Not run: client <- hb_client() hb_update_select_option(client, "Samples", "Status", "Done", "Complete") ## End(Not run)## Not run: client <- hb_client() hb_update_select_option(client, "Samples", "Status", "Done", "Complete") ## End(Not run)
SeaTable's API addresses one view by its name in the URL, and its server reads a slash in that name as a path separator and a name of one or two dots as a folder. Such a view cannot be changed through the API, and harbouR says so before sending anything: rename it in SeaTable first.
hb_update_view(client, table, view, settings, ...)hb_update_view(client, table, view, settings, ...)
client |
A |
table |
Table name. |
view |
Name of the view to update. |
settings |
Named list of the fields to change: |
... |
These dots are for future extensions and must be empty. |
Invisibly returns the client.
Other views:
hb_create_view(),
hb_delete_view(),
hb_get_view(),
hb_list_views()
## Not run: client <- hb_client() hb_update_view(client, "Samples", "Active", list(filter_conjunction = "And")) ## End(Not run)## Not run: client <- hb_client() hb_update_view(client, "Samples", "Active", list(filter_conjunction = "And")) ## End(Not run)
Uploads path to the active base and returns the SeaTable file object
(a named list with name, size, type and url) ready to be written
into a file-typed cell via hb_update_rows() or hb_attach_file().
hb_upload_file(client, path, ..., relative_path = "files")hb_upload_file(client, path, ..., relative_path = "files")
client |
A |
path |
Local file path. Must exist. |
... |
These dots are for future extensions and must be empty. |
relative_path |
Folder under the base's asset root. The default,
|
SeaTable's file endpoints authenticate with the base's API token, so
this needs a client created with api_token; a username/password
client gets a harbour_error_auth condition.
A finite client timeout bounds the complete upload request. A timeout can occur after the server has accepted the file; it does not establish that the upload was rolled back. Check the server before retrying to avoid creating a duplicate attachment. Uploads are not retried automatically.
A named list describing the uploaded asset.
Other files:
hb_attach_file(),
hb_delete_asset(),
hb_download_file()
## Not run: client <- hb_client() hb_upload_file(client, "report.pdf") ## End(Not run)## Not run: client <- hb_client() hb_upload_file(client, "report.pdf") ## End(Not run)
Reports structural issues that would make SeaTable reject the file, or
that indicate the base was built incorrectly in R: missing top-level
keys; a table without a name or an _id; repeated table names, table
ids, column keys, column names or row ids; a column without a key, a
type or a name, or one named _id; rows without an _id; and empty
table or view settings that would be written as [] where SeaTable
expects {}.
hb_validate_dtable(x, ...)hb_validate_dtable(x, ...)
x |
A |
... |
These dots are for future extensions and must be empty. |
A tibble with columns location (chr), problem (chr) and
severity (chr, "error" or "warning"). Zero rows means the base
is well-formed.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
base <- hb_dtable(Samples = data.frame(x = 1)) hb_validate_dtable(base)base <- hb_dtable(Samples = data.frame(x = 1)) hb_validate_dtable(base)
Writes one .csv per table into dir. Subject to the same losses as
hb_write_xlsx(); see its documentation. Each file is named after its
table, with the characters a file name cannot hold on some system -
/ \ : * ? " < > | and control characters - replaced by _. Table
names that produce the same filename (ignoring case) are rejected
before any files are written.
hb_write_csv(x, dir, ..., tables = NULL)hb_write_csv(x, dir, ..., tables = NULL)
x |
A |
dir |
Destination directory. Created if it does not exist. |
... |
These dots are for future extensions and must be empty. |
tables |
Table names to export. Default: all of them. |
A character vector of the files written, invisibly.
hb_write_xlsx(), hb_write_dtable()
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
base <- hb_read_dtable( system.file("extdata", "example.dtable", package = "harbouR") ) dir <- tempfile() hb_write_csv(base, dir) list.files(dir)base <- hb_read_dtable( system.file("extdata", "example.dtable", package = "harbouR") ) dir <- tempfile() hb_write_csv(base, dir) list.files(dir)
harbour_dtable back to a .dtable fileProduces a ZIP archive SeaTable can import. Round-tripping is lossless:
reading a file and writing it back yields a content.json that parses
to an identical structure, verified against a real 750 KB export. The
attachments go back in too when the file was read with
assets = "extract".
hb_write_dtable(x, path, ..., assets = TRUE, overwrite = TRUE)hb_write_dtable(x, path, ..., assets = TRUE, overwrite = TRUE)
x |
A |
path |
Destination path. |
... |
These dots are for future extensions and must be empty. |
assets |
Whether to repack the extracted asset tree, if there is
one. Default |
overwrite |
Whether to replace an existing file at |
The archive is built in a temporary file beside path and moved into
place only once it is complete, so a failed write cannot destroy the
file it replaces - even when that is the file the base was read from.
Replacing a file gives it a new identity on disk, so any other hard
link to it keeps the old content. Where no new file can be made beside
path, or there is nothing at path to lose - an empty file such as
/dev/null, or a link to a file not made yet - the archive is written
straight into it. A file that cannot be replaced, because another
program holds it open or the folder lets files be written but not
removed, is written into once the archive is complete; that needs room
for a second copy, and should it fail, the complete archive is kept
beside path and the error says where. A symbolic link in the
extracted asset tree is left out, with a warning, rather than followed
to wherever it points, including when asset/ itself is a link.
Recorded attachments whose extracted files are missing are left out
with a warning of class harbour_warning_missing_assets naming them.
x, invisibly.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
path <- system.file("extdata", "example.dtable", package = "harbouR") # extract the assets, so the attachments are written back too base <- hb_read_dtable(path, assets = "extract") out <- tempfile(fileext = ".dtable") hb_write_dtable(base, out) # content.json round-trips exactly identical(hb_read_dtable(out)$content, base$content)path <- system.file("extdata", "example.dtable", package = "harbouR") # extract the assets, so the attachments are written back too base <- hb_read_dtable(path, assets = "extract") out <- tempfile(fileext = ".dtable") hb_write_dtable(base, out) # content.json round-trips exactly identical(hb_read_dtable(out)$content, base$content)
Writes one worksheet per table. This is deliberately one-way: a spreadsheet cell holds a single value, so several SeaTable column types have no faithful representation.
hb_write_xlsx(x, path, ..., tables = NULL)hb_write_xlsx(x, path, ..., tables = NULL)
x |
A |
path |
Destination |
... |
These dots are for future extensions and must be empty. |
tables |
Table names to export. Default: all of them. |
Each sheet is named after its table, made to fit Excel's rules for
sheet names: cut to 31 characters, with each of /, \, ?, *,
: or a square bracket replaced by _. Excel compares sheet names
ignoring case, so table names that would give sheet names differing
only in the case of the letters A to Z, such as Samples and
samples, are rejected before anything is written. So is text longer
than the 32,767 characters a workbook cell holds.
path, invisibly.
multiple-select, collaborator and image cells are joined with
", ".
file cells are reduced to their file names.
link and link-formula cells reference rows in other tables and
are exported as their display values.
formula columns export their computed value, not the formula.
geolocation cells are written as their values, in the order the
source stores them, without the field names: "11.5761, 48.1371"
does not say which number is the latitude.
digital-sign cells are written as a placeholder, "<object>", or
as their bare values, depending on how the source stores them; the
signature itself is not exported. button columns hold no value and
are written as missing.
A CSV stores numbers with 15 significant digits and a workbook with
16, so a double that needs more, such as 0.1 + 0.2, reads back very
slightly different. In a CSV, date-times are written by
as.character(), whose layout depends on the version of R. Use
hb_write_dtable() for full precision.
Views, filters, colours, column widths and every other piece of base configuration have no cell to live in.
harbouR reports which columns were flattened. To keep everything, write
a .dtable with hb_write_dtable() instead.
hb_write_csv(), hb_write_dtable()
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
base <- hb_read_dtable( system.file("extdata", "example.dtable", package = "harbouR") ) out <- tempfile(fileext = ".xlsx") hb_write_xlsx(base, out)base <- hb_read_dtable( system.file("extdata", "example.dtable", package = "harbouR") ) out <- tempfile(fileext = ".xlsx") hb_write_xlsx(base, out)
Test whether an object is a harbour client
is_harbour_client(x)is_harbour_client(x)
x |
Object to test. |
A single TRUE or FALSE.
Other client:
hb_check_credentials(),
hb_client(),
hb_ping(),
hb_server_info()
# creating a client does not contact the server client <- hb_client( server = "https://seatable.example.org", api_token = "your-api-token" ) is_harbour_client(client) is_harbour_client(list())# creating a client does not contact the server client <- hb_client( server = "https://seatable.example.org", api_token = "your-api-token" ) is_harbour_client(client) is_harbour_client(list())
Test whether an object is a harbour dtable
is_harbour_dtable(x)is_harbour_dtable(x)
x |
Object to test. |
A single TRUE or FALSE.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
is_harbour_dtable(hb_dtable(Samples = data.frame(x = 1)))is_harbour_dtable(hb_dtable(Samples = data.frame(x = 1)))
Test whether an object is harbour metadata
is_harbour_metadata(x)is_harbour_metadata(x)
x |
Object to test. |
A single TRUE or FALSE.
Other metadata:
as_tibble.harbour_metadata(),
hb_column_types(),
hb_list_collaborators(),
hb_list_tables(),
hb_metadata(),
print.harbour_metadata(),
summary.harbour_metadata()
is_harbour_metadata(hb_example_metadata()) is_harbour_metadata(list())is_harbour_metadata(hb_example_metadata()) is_harbour_metadata(list())
Number of tables in a dtable
## S3 method for class 'harbour_dtable' length(x)## S3 method for class 'harbour_dtable' length(x)
x |
A |
A single integer.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
length(hb_dtable(Samples = data.frame(x = 1)))length(hb_dtable(Samples = data.frame(x = 1)))
Names of the tables in a dtable
## S3 method for class 'harbour_dtable' names(x)## S3 method for class 'harbour_dtable' names(x)
x |
A |
A character vector of table names.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
print.harbour_dtable(),
summary.harbour_dtable()
names(hb_dtable(Samples = data.frame(x = 1), Notes = data.frame(y = 2)))names(hb_dtable(Samples = data.frame(x = 1), Notes = data.frame(y = 2)))
Print a harbour dtable
## S3 method for class 'harbour_dtable' print(x, ...) ## S3 method for class 'harbour_dtable' format(x, ...)## S3 method for class 'harbour_dtable' print(x, ...) ## S3 method for class 'harbour_dtable' format(x, ...)
x |
A |
... |
These dots are for future extensions and must be empty. |
print() returns x, invisibly.
format() returns a character vector, one element per table.
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
summary.harbour_dtable()
print(hb_dtable(Samples = data.frame(x = 1)))print(hb_dtable(Samples = data.frame(x = 1)))
Print method for harbour metadata
## S3 method for class 'harbour_metadata' print(x, ...) ## S3 method for class 'harbour_metadata' format(x, ...)## S3 method for class 'harbour_metadata' print(x, ...) ## S3 method for class 'harbour_metadata' format(x, ...)
x |
A |
... |
These dots are for future extensions and must be empty. |
print() returns x, invisibly.
format() returns a character vector, one element per table.
Other metadata:
as_tibble.harbour_metadata(),
hb_column_types(),
hb_list_collaborators(),
hb_list_tables(),
hb_metadata(),
is_harbour_metadata(),
summary.harbour_metadata()
meta <- hb_example_metadata() print(meta) format(meta)meta <- hb_example_metadata() print(meta) format(meta)
Summarise the schema of a dtable
## S3 method for class 'harbour_dtable' summary(object, ...)## S3 method for class 'harbour_dtable' summary(object, ...)
object |
A |
... |
These dots are for future extensions and must be empty. |
A tibble with one row per column across all tables: table
(chr), column (chr), type (chr), key (chr).
Other dtable:
as_tibble.harbour_dtable(),
hb_asset_path(),
hb_dtable(),
hb_read_csv(),
hb_read_dtable(),
hb_read_xlsx(),
hb_validate_dtable(),
hb_write_csv(),
hb_write_dtable(),
hb_write_xlsx(),
is_harbour_dtable(),
length.harbour_dtable(),
names.harbour_dtable(),
print.harbour_dtable()
summary(hb_dtable(Samples = data.frame(x = 1, y = "a")))summary(hb_dtable(Samples = data.frame(x = 1, y = "a")))
Summary of harbour metadata
## S3 method for class 'harbour_metadata' summary(object, ...)## S3 method for class 'harbour_metadata' summary(object, ...)
object |
A |
... |
These dots are for future extensions and must be empty. |
A tibble with one row per column across all tables, suitable for
inspecting the SeaTable schema. Columns: table (chr), column (chr),
type (chr).
Other metadata:
as_tibble.harbour_metadata(),
hb_column_types(),
hb_list_collaborators(),
hb_list_tables(),
hb_metadata(),
is_harbour_metadata(),
print.harbour_metadata()
summary(hb_example_metadata())summary(hb_example_metadata())