Add export options and in-memory SQL export#193
Conversation
The JS SDK's export(options) can filter what gets exported (users, accesses, params, functions, analyzers, versions, records, tables, ...) and returns the export as a string, while the Java SDK only offered exportSql(String path) with no filtering. Add com.surrealdb.ExportOptions, a builder mirroring the Rust SDK's export .with_config() options, plus exportSql(path, options), exportSql(options) and exportSql() which return the export in memory as a String by collecting the byte stream from export(()). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
emmanuel-keller
left a comment
There was a problem hiding this comment.
Review — approve with nits.
Plumbing checks out end-to-end: the flag bits match bit-for-bit between ExportOptions and the Rust EXPORT_FLAG_*, every flag maps to the right with_config() setter, and the defaults match Config::default() (all-true except versions, with sequences staying on — accurately documented). Mid-stream stream errors propagate (no truncated string is ever returned) and non-UTF-8 surfaces as a clean exception. No native handle allocated, so no leak.
Test gaps: no empty-database export; no non-ASCII/multibyte content test (the one case that actually exercises the new from_utf8/new_string path); several flags (versions(true), users/accesses/analyzers/apis/buckets/modules/configs) untested (mechanically identical to the tested ones, so low risk).
| * @throws SurrealException | ||
| * if export fails or backups are not supported | ||
| */ | ||
| public String exportSql() { |
There was a problem hiding this comment.
Worth a Javadoc note here: the in-memory variant buffers the whole export (Rust Vec<u8> → String → JVM UTF-16, so ~3x peak memory), there's no size guard, and new_string can't represent a >2 GB modified-UTF-8 payload. It's a reasonable tradeoff (matches the JS SDK's string return, and the file overload exists for large DBs) — just point large exports at exportSql(String, ...).
There was a problem hiding this comment.
Added in cc1ade3: both in-memory variants (exportSql() and exportSql(ExportOptions)) now carry a Javadoc note that the whole export is buffered in memory (native byte buffer then copied to a UTF-16 String, so roughly 3x peak memory), that there is no size guard, that exports larger than 2 GB cannot be represented as a single Java string, and that large databases should use the file overloads exportSql(String) / exportSql(String, ExportOptions).
| * the names of the tables to export | ||
| * @return this instance for chaining | ||
| */ | ||
| public ExportOptions tables(String... tables) { |
There was a problem hiding this comment.
tables(String...) with zero args produces a non-null empty array → TableConfig::Some(vec![]) → exports no tables. new ExportOptions().tables() returning nothing is surprising; consider treating an empty list as "all", or documenting it. (Also allTables stays true here, so FLAG_TABLES is still set but ignored native-side when the list is Some — dead in that path.)
There was a problem hiding this comment.
Fixed in cc1ade3. tables() with zero args is now equivalent to tables(true) — it exports all tables instead of none — and the Javadoc documents that empty means all. The dead-path issue is resolved too: setting a non-empty list now clears the all-tables flag, so FLAG_TABLES is never set alongside an explicit list (the native side already gives the list precedence; the Java side just no longer sends the ignored bit). Added tablesEmptyVarargs_exportsAllTables to pin the behaviour, including that a zero-arg call replaces a previously set narrower list.
| * @throws SurrealException | ||
| * if export fails or backups are not supported | ||
| */ | ||
| public boolean exportSql(String path, ExportOptions options) { |
There was a problem hiding this comment.
exportSql(String, ExportOptions) / exportSql(ExportOptions) throw a raw NPE if options is null (the no-arg overload is safe). Worth a @throws NullPointerException note or an explicit guard.
There was a problem hiding this comment.
Fixed in cc1ade3: both exportSql(String, ExportOptions) and exportSql(ExportOptions) now guard with Objects.requireNonNull(options, "options") and document @throws NullPointerException if options is null. Added nullOptions_throwNullPointerException covering both overloads.
- exportSql(String, ExportOptions) and exportSql(ExportOptions) throw NullPointerException with a message when options is null (@throws documented) instead of a raw NPE from inside the call. - ExportOptions.tables() with zero arguments is now equivalent to tables(true) (export all tables) rather than exporting no tables, and setting a non-empty list clears the all-tables flag so FLAG_TABLES is never set alongside an explicit list. - Javadoc on the in-memory export variants documents that the whole export is buffered (~3x peak memory), has no size guard, cannot exceed 2 GB as a single Java string, and points large exports at the file overloads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
JS-parity gap
The JS SDK's
export(options)(packages/sdk/src/api/surreal.ts,SqlExportOptions) can filter what an export contains (users,accesses,params,functions,analyzers,apis,buckets,modules,configs,sequences,versions,records, andtables: boolean | string[]) and returns the export as a string. The Java SDK only offeredexportSql(String path): file-path only, no options, no in-memory result.Reproduction
On the embedded
memoryengine: createdperson/cityrecords, aDEFINE FUNCTIONand aDEFINE PARAM, then calledexportSql(path). The export always contains all sections (OPTION, PARAMS, FUNCTIONS, table definitions, andINSERTtable data) and there is no API to exclude any of them, nor to obtain the export without going through a file.Rust SDK capability (surrealdb 3.1.5)
src/method/export.rssupports both halves of the gap:export(target).with_config()exposes builder filters:users,accesses,params,functions,analyzers,apis,buckets,modules,configs,versions,records, andtables(impl Into<TableConfig>)(acceptingboolor aVec<String>table list).export(())resolves to aBackupstream of byte chunks, i.e. an in-memory export.Note: the JS
sequencesoption has no counterpart in the Rust 3.1.5with_config()builder, so it is not exposed here (it stays at its server default, included). Everything else in the JS option set maps 1:1.Fix
com.surrealdb.ExportOptionsbuilder covering exactly the Rust SDK's config options:users,accesses,params,functions,analyzers,apis,buckets,modules,configs,versions,records,tables(boolean)/tables(String...). Defaults mirror the server defaults (everything on exceptversions).Surreal.exportSql(String path, ExportOptions options)— filtered export to a file.Surreal.exportSql(ExportOptions options)andSurreal.exportSql()— in-memory export returned as aString, collected from the Rust byte stream.exportSql(String path)is unchanged.exportSqlOptions/exportSqlStringinsrc/main/rust/surreal.rs): the boolean options travel as anintbitmask (constants kept in sync betweenExportOptions.javaandsurreal.rs) plus a nullableString[]for an explicit table list, which takes precedence over the all-tables bit.Tests
New
ExportOptionsTests(memory engine, export/import is not supported over WebSocket):records(false)dropsINSERTdata but keepsDEFINE TABLE;tables("person")limits which tables appear;tables(false)drops all tables while keeping functions;functions(false).params(false)drops those definitions;importSql, records and function intact.Full
./gradlew testsuite passes;spotlessApplyandcargo fmt --checkclean.🤖 Generated with Claude Code