fresh-borzoni commented on code in PR #300:
URL: https://github.com/apache/fluss-rust/pull/300#discussion_r2804930425


##########
website/docs/user-guide/python/api-reference.md:
##########
@@ -0,0 +1,281 @@
+---
+sidebar_position: 2
+---
+# API Reference
+
+Complete API reference for the Fluss Python client.
+
+## `Config`
+
+| Method / Property                 | Description                              
    |
+|-----------------------------------|----------------------------------------------|

Review Comment:
   it doesn't look complete



##########
website/docs/user-guide/python/example/configuration.md:
##########
@@ -0,0 +1,34 @@
+---
+sidebar_position: 2
+---
+# Configuration
+
+```python
+import fluss
+
+config = fluss.Config({"bootstrap.servers": "127.0.0.1:9123"})
+conn = await fluss.FlussConnection.create(config)
+```
+
+The connection also supports context managers:
+
+```python
+with await fluss.FlussConnection.create(config) as conn:
+    ...
+```
+
+## Configuration Options
+
+| Key                 | Description                                           
| Default            |
+|---------------------|-------------------------------------------------------|--------------------|
+| `bootstrap.servers` | Coordinator server address                            
| `127.0.0.1:9123`   |
+| `request.max.size`  | Maximum request size in bytes                         
| `10485760` (10 MB) |
+| `writer.acks`       | Acknowledgment setting (`all` waits for all replicas) 
| `all`              |
+| `writer.retries`    | Number of retries on failure                          
| `2147483647`       |
+| `writer.batch.size` | Batch size for writes in bytes                        
| `2097152` (2 MB)   |

Review Comment:
   I think we have different dict keys in config, with '-', but it's my editor 
played funny auto-completion, so I'll fix to match this doc



##########
website/docs/user-guide/python/error-handling.md:
##########
@@ -0,0 +1,19 @@
+---
+sidebar_position: 4
+---
+# Error Handling
+
+The client raises `fluss.FlussError` for Fluss-specific errors:
+
+```python

Review Comment:
   Shall we add more details to error handling? Python looks surprisingly thin 
:)
   no error_code explanation or anything



##########
website/docs/user-guide/rust/example/partitioned-tables.md:
##########
@@ -0,0 +1,215 @@
+---
+sidebar_position: 6
+---
+# Partitioned Tables
+
+Partitioned tables distribute data across partitions based on partition column 
values, enabling efficient data organization and querying. Both log tables and 
primary key tables support partitioning.
+
+## Partitioned Log Tables
+
+### Creating a Partitioned Log Table
+
+```rust
+use fluss::metadata::{DataTypes, LogFormat, Schema, TableDescriptor, 
TablePath};
+
+let table_descriptor = TableDescriptor::builder()
+    .schema(
+        Schema::builder()
+            .column("event_id", DataTypes::int())
+            .column("event_type", DataTypes::string())
+            .column("dt", DataTypes::string())
+            .column("region", DataTypes::string())
+            .build()?,
+    )
+    .partitioned_by(vec!["dt", "region"])
+    .log_format(LogFormat::ARROW)
+    .build()?;
+
+let table_path = TablePath::new("fluss", "partitioned_events");
+admin.create_table(&table_path, &table_descriptor, true).await?;
+```
+
+### Writing to Partitioned Log Tables
+
+**Partitions must exist before writing data, otherwise the client will by 
default retry indefinitely.** Include partition column values in each row, the 
client routes records to the correct partition automatically.
+
+```rust
+use fluss::metadata::PartitionSpec;
+use std::collections::HashMap;
+
+let table = conn.get_table(&table_path).await?;
+
+// Create the partition before writing
+let mut partition_values = HashMap::new();
+partition_values.insert("dt", "2024-01-15");
+partition_values.insert("region", "US");
+admin.create_partition(&table_path, &PartitionSpec::new(partition_values), 
true).await?;
+
+let append_writer = table.new_append()?.create_writer()?;
+
+let mut row = GenericRow::new(4);
+row.set_field(0, 1);              // event_id
+row.set_field(1, "user_login");   // event_type
+row.set_field(2, "2024-01-15");   // dt (partition column)
+row.set_field(3, "US");           // region (partition column)
+
+append_writer.append(&row)?;
+append_writer.flush().await?;
+```
+
+### Reading from Partitioned Log Tables
+
+For partitioned tables, use partition-aware subscribe methods.
+
+```rust
+use std::time::Duration;
+
+let table = conn.get_table(&table_path).await?;
+let admin = conn.get_admin().await?;
+let partitions = admin.list_partition_infos(&table_path).await?;
+
+let log_scanner = table.new_scan().create_log_scanner()?;
+
+// Subscribe to each partition's buckets
+for partition_info in &partitions {
+    let partition_id = partition_info.get_partition_id();
+    let num_buckets = table.get_table_info().get_num_buckets();
+    for bucket_id in 0..num_buckets {
+        log_scanner.subscribe_partition(partition_id, bucket_id, 0).await?;
+    }
+}
+
+let records = log_scanner.poll(Duration::from_secs(10)).await?;
+for record in records {
+    println!("Record: {:?}", record.row());
+}
+```
+
+Subscribe to multiple partition-buckets at once:
+
+```rust
+use std::collections::HashMap;
+
+let mut partition_bucket_offsets = HashMap::new();
+partition_bucket_offsets.insert((partition_id, 0), 0i64);
+partition_bucket_offsets.insert((partition_id, 1), 0i64);
+log_scanner.subscribe_partition_buckets(&partition_bucket_offsets).await?;
+```
+
+### Managing Partitions
+
+```rust
+use fluss::metadata::PartitionSpec;
+use std::collections::HashMap;
+
+// Create a partition
+let mut partition_values = HashMap::new();
+partition_values.insert("dt", "2024-01-15");
+partition_values.insert("region", "EMEA");
+let spec = PartitionSpec::new(partition_values);
+admin.create_partition(&table_path, &spec, true).await?;
+
+// List all partitions
+let partitions = admin.list_partition_infos(&table_path).await?;
+for partition in &partitions {
+    println!(
+        "Partition: id={}, name={}",
+        partition.get_partition_id(),
+        partition.get_partition_name()
+    );
+}
+
+// List with filter
+let mut partial_values = HashMap::new();
+partial_values.insert("dt", "2024-01-15");
+let partial_spec = PartitionSpec::new(partial_values);
+let filtered = admin.list_partition_infos_with_spec(

Review Comment:
   ditto



##########
website/docs/user-guide/cpp/example/admin-operations.md:
##########
@@ -0,0 +1,107 @@
+---
+sidebar_position: 3
+---
+# Admin Operations
+
+## Get Admin Interface
+
+```cpp
+fluss::Admin admin;
+conn.GetAdmin(admin);
+```
+
+## Table Operations
+
+```cpp
+fluss::TablePath table_path("fluss", "my_table");
+
+auto schema = fluss::Schema::NewBuilder()
+    .AddColumn("id", fluss::DataType::Int())
+    .AddColumn("name", fluss::DataType::String())
+    .AddColumn("score", fluss::DataType::Float())
+    .AddColumn("age", fluss::DataType::Int())
+    .Build();
+
+auto descriptor = fluss::TableDescriptor::NewBuilder()
+    .SetSchema(schema)
+    .SetBucketCount(3)
+    .SetComment("Example table")
+    .Build();
+
+// Create table
+admin.CreateTable(table_path, descriptor, true);
+
+// Get table information
+fluss::TableInfo table_info;
+admin.GetTableInfo(table_path, table_info);
+std::cout << "Table ID: " << table_info.table_id << std::endl;
+std::cout << "Number of buckets: " << table_info.num_buckets << std::endl;
+std::cout << "Has primary key: " << table_info.has_primary_key << std::endl;
+std::cout << "Is partitioned: " << table_info.is_partitioned << std::endl;
+
+// Drop table
+admin.DropTable(table_path, true);
+```
+
+## Schema Builder Options
+
+```cpp
+// Schema with primary key
+auto pk_schema = fluss::Schema::NewBuilder()
+    .AddColumn("id", fluss::DataType::Int())
+    .AddColumn("name", fluss::DataType::String())
+    .AddColumn("value", fluss::DataType::Double())
+    .SetPrimaryKeys({"id"})
+    .Build();
+
+// Table descriptor with partitioning
+auto descriptor = fluss::TableDescriptor::NewBuilder()
+    .SetSchema(schema)
+    .SetPartitionKeys({"date"})
+    .SetBucketCount(3)
+    .SetBucketKeys({"user_id"})
+    .SetProperty("retention_days", "7")
+    .SetComment("Sample table")
+    .Build();
+```
+
+## Offset Operations
+
+```cpp
+std::vector<int32_t> bucket_ids = {0, 1, 2};
+
+// Query earliest offsets
+std::unordered_map<int32_t, int64_t> earliest_offsets;
+admin.ListOffsets(table_path, bucket_ids,
+                  fluss::OffsetQuery::Earliest(), earliest_offsets);
+
+// Query latest offsets
+std::unordered_map<int32_t, int64_t> latest_offsets;
+admin.ListOffsets(table_path, bucket_ids,
+                  fluss::OffsetQuery::Latest(), latest_offsets);
+
+// Query offsets for a specific timestamp
+std::unordered_map<int32_t, int64_t> timestamp_offsets;
+admin.ListOffsets(table_path, bucket_ids,
+                  fluss::OffsetQuery::FromTimestamp(timestamp_ms),
+                  timestamp_offsets);
+
+// Query partition offsets
+std::unordered_map<int32_t, int64_t> partition_offsets;
+admin.ListPartitionOffsets(table_path, "partition_name",
+                           bucket_ids, fluss::OffsetQuery::Latest(),
+                           partition_offsets);
+```
+
+## Lake Snapshot
+
+```cpp
+fluss::LakeSnapshot snapshot;
+admin.GetLatestLakeSnapshot(table_path, snapshot);
+std::cout << "Snapshot ID: " << snapshot.snapshot_id << std::endl;
+for (const auto& bucket_offset : snapshot.bucket_offsets) {
+    std::cout << "  Table " << bucket_offset.table_id
+              << ", Bucket " << bucket_offset.bucket_id
+              << ": offset=" << bucket_offset.offset << std::endl;
+}
+```

Review Comment:
   create/list/drop database? other admin docs have it



##########
website/docs/user-guide/rust/example/admin-operations.md:
##########
@@ -0,0 +1,118 @@
+---
+sidebar_position: 3
+---
+# Admin Operations
+
+## Get Admin Interface
+
+```rust
+let admin = conn.get_admin().await?;
+```
+
+## Database Operations
+
+```rust
+// Create database
+admin.create_database("my_database", None, true).await?;
+
+// List all databases
+let databases = admin.list_databases().await?;
+println!("Databases: {:?}", databases);
+
+// Check if database exists
+let exists = admin.database_exists("my_database").await?;
+
+// Get database information
+let db_info = admin.get_database_info("my_database").await?;
+
+// Drop database
+admin.drop_database("my_database", true, false).await?;
+```
+
+## Table Operations
+
+```rust
+use fluss::metadata::{DataTypes, Schema, TableDescriptor, TablePath};
+
+let table_descriptor = TableDescriptor::builder()
+    .schema(
+        Schema::builder()
+            .column("id", DataTypes::int())
+            .column("name", DataTypes::string())
+            .column("amount", DataTypes::bigint())
+            .build()?,
+    )
+    .build()?;
+
+let table_path = TablePath::new("my_database", "my_table");
+
+// Create table
+admin.create_table(&table_path, &table_descriptor, true).await?;
+
+// Get table information
+let table_info = admin.get_table_info(&table_path).await?;
+println!("Table: {}", table_info);
+
+// List tables in database
+let tables = admin.list_tables("my_database").await?;
+
+// Check if table exists
+let exists = admin.table_exists(&table_path).await?;
+
+// Drop table
+admin.drop_table(&table_path, true).await?;
+```
+
+## Partition Operations
+
+```rust
+use fluss::metadata::PartitionSpec;
+use std::collections::HashMap;
+
+// List all partitions
+let partitions = admin.list_partition_infos(&table_path).await?;
+
+// List partitions matching a spec
+let mut filter = HashMap::new();
+filter.insert("year", "2024");
+let spec = PartitionSpec::new(filter);
+let partitions = admin.list_partition_infos_with_spec(&table_path, 
Some(&spec)).await?;

Review Comment:
   Also, maybe we wish to add this method to python/c++ since it's public and 
useful to filter on server



##########
website/docs/user-guide/cpp/api-reference.md:
##########
@@ -0,0 +1,494 @@
+---
+sidebar_position: 2
+---
+# API Reference
+
+Complete API reference for the Fluss C++ client.
+
+## `Result`
+
+| Field / Method  | Type          | Description                                
                    |
+|-----------------|---------------|----------------------------------------------------------------|
+| `error_code`    | `int32_t`     | 0 for success, non-zero for errors         
                    |
+| `error_message` | `std::string` | Human-readable error description           
                    |
+| `Ok()`          | `bool`        | Returns `true` if operation succeeded 
(`error_code == 0`)      |
+
+## `Configuration`
+
+| Field                             | Type          | Default              | 
Description                                                     |
+|-----------------------------------|---------------|----------------------|-----------------------------------------------------------------|
+| `bootstrap_servers`               | `std::string` | `"127.0.0.1:9123"`   | 
Coordinator server address                                      |
+| `writer_request_max_size`         | `int32_t`     | `10485760` (10 MB)   | 
Maximum request size in bytes                                   |
+| `writer_acks`                     | `std::string` | `"all"`              | 
Acknowledgment setting (`"all"`, `"0"`, `"1"`, or `"-1"`)       |
+| `writer_retries`                  | `int32_t`     | `INT32_MAX`          | 
Number of retries on failure                                    |
+| `writer_batch_size`               | `int32_t`     | `2097152` (2 MB)     | 
Batch size for writes in bytes                                  |
+| `scanner_remote_log_prefetch_num` | `size_t`      | `4`                  | 
Number of remote log segments to prefetch                       |
+| `remote_file_download_thread_num` | `size_t`      | `3`                  | 
Number of threads for remote log downloads                      |
+
+## `Connection`
+
+| Method                                                                  | 
Description                                       |
+|-------------------------------------------------------------------------|---------------------------------------------------|
+| `static Create(const Configuration& config, Connection& out) -> Result` | 
Create a connection to a Fluss cluster            |
+| `GetAdmin(Admin& out) -> Result`                                        | 
Get the admin interface                           |
+| `GetTable(const TablePath& table_path, Table& out) -> Result`           | 
Get a table for read/write operations             |
+| `Available() -> bool`                                                   | 
Check if the connection is valid and initialized  |
+
+## `Admin`
+
+### Database Operations
+
+| Method                                                                       
                                             | Description              |
+|---------------------------------------------------------------------------------------------------------------------------|--------------------------|
+| `CreateDatabase(const std::string& database_name, const DatabaseDescriptor& 
descriptor, bool ignore_if_exists) -> Result` | Create a database        |
+| `DropDatabase(const std::string& name, bool ignore_if_not_exists, bool 
cascade) -> Result`                                | Drop a database          |
+| `ListDatabases(std::vector<std::string>& out) -> Result`                     
                                             | List all databases       |
+| `DatabaseExists(const std::string& name, bool& out) -> Result`               
                                             | Check if a database exists |
+| `GetDatabaseInfo(const std::string& name, DatabaseInfo& out) -> Result`      
                                             | Get database metadata    |
+
+### Table Operations
+
+| Method                                                                       
                              | Description                 |
+|------------------------------------------------------------------------------------------------------------|-----------------------------|
+| `CreateTable(const TablePath& path, const TableDescriptor& descriptor, bool 
ignore_if_exists) -> Result`   | Create a table              |
+| `DropTable(const TablePath& path, bool ignore_if_not_exists) -> Result`      
                              | Drop a table                |
+| `GetTableInfo(const TablePath& path, TableInfo& out) -> Result`              
                              | Get table metadata          |
+| `ListTables(const std::string& database_name, std::vector<std::string>& out) 
-> Result`                    | List tables in a database   |
+| `TableExists(const TablePath& path, bool& out) -> Result`                    
                              | Check if a table exists     |
+
+### Partition Operations
+
+| Method                                                                       
                                                                   | 
Description              |
+|-------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|
+| `CreatePartition(const TablePath& path, const 
std::unordered_map<std::string, std::string>& partition_spec, bool 
ignore_if_exists) -> Result`   | Create a partition       |
+| `DropPartition(const TablePath& path, const std::unordered_map<std::string, 
std::string>& partition_spec, bool ignore_if_not_exists) -> Result` | Drop a 
partition         |
+| `ListPartitionInfos(const TablePath& path, std::vector<PartitionInfo>& out) 
-> Result`                                                          | List 
partition metadata  |
+
+### Offset Operations
+
+| Method                                                                       
                                                                                
                                           | Description                        
     |
+|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|
+| `ListOffsets(const TablePath& path, const std::vector<int32_t>& bucket_ids, 
const OffsetQuery& query, std::unordered_map<int32_t, int64_t>& out) -> Result` 
                                            | Get offsets for buckets           
      |
+| `ListPartitionOffsets(const TablePath& path, const std::string& 
partition_name, const std::vector<int32_t>& bucket_ids, const OffsetQuery& 
query, std::unordered_map<int32_t, int64_t>& out) -> Result` | Get offsets for 
a partition's buckets   |
+
+### Lake Operations
+
+| Method                                                                      
| Description                  |
+|-----------------------------------------------------------------------------|------------------------------|
+| `GetLatestLakeSnapshot(const TablePath& path, LakeSnapshot& out) -> Result` 
| Get the latest lake snapshot |
+
+## `Table`
+
+| Method                        | Description                              |
+|-------------------------------|------------------------------------------|
+| `NewRow() -> GenericRow`      | Create a schema-aware row for this table |
+| `NewAppend() -> TableAppend`  | Create an append builder for log tables  |
+| `NewUpsert() -> TableUpsert`  | Create an upsert builder for PK tables   |
+| `NewLookup() -> TableLookup`  | Create a lookup builder for PK tables    |
+| `NewScan() -> TableScan`      | Create a scan builder                    |
+| `GetTableInfo() -> TableInfo` | Get table metadata                       |
+| `GetTablePath() -> TablePath` | Get the table path                       |
+| `HasPrimaryKey() -> bool`     | Check if the table has a primary key     |
+
+## `TableAppend`
+
+| Method                                       | Description             |
+|----------------------------------------------|-------------------------|
+| `CreateWriter(AppendWriter& out) -> Result`  | Create an append writer |
+
+## `TableUpsert`
+
+| Method                                                                       
| Description                                |
+|------------------------------------------------------------------------------|--------------------------------------------|
+| `PartialUpdateByIndex(std::vector<size_t> column_indices) -> TableUpsert&`   
| Configure partial update by column indices |
+| `PartialUpdateByName(std::vector<std::string> column_names) -> TableUpsert&` 
| Configure partial update by column names   |
+| `CreateWriter(UpsertWriter& out) -> Result`                                  
| Create an upsert writer                    |
+
+## `TableLookup`
+
+| Method                                    | Description                      
   |
+|-------------------------------------------|-------------------------------------|
+| `CreateLookuper(Lookuper& out) -> Result` | Create a lookuper for point 
lookups |
+
+## `TableScan`
+
+| Method                                                               | 
Description                                   |
+|----------------------------------------------------------------------|-----------------------------------------------|
+| `ProjectByIndex(std::vector<size_t> column_indices) -> TableScan&`   | 
Project columns by index                      |
+| `ProjectByName(std::vector<std::string> column_names) -> TableScan&` | 
Project columns by name                       |
+| `CreateLogScanner(LogScanner& out) -> Result`                        | 
Create a record-based log scanner             |
+| `CreateRecordBatchLogScanner(LogScanner& out) -> Result`             | 
Create an Arrow RecordBatch-based log scanner |
+
+## `AppendWriter`
+
+| Method                                                      | Description    
                        |
+|-------------------------------------------------------------|----------------------------------------|
+| `Append(const GenericRow& row) -> Result`                   | Append a row 
(fire-and-forget)         |
+| `Append(const GenericRow& row, WriteResult& out) -> Result` | Append a row 
with write acknowledgment |
+| `Flush() -> Result`                                         | Flush all 
pending writes               |
+
+## `UpsertWriter`
+
+| Method                                                      | Description    
                               |
+|-------------------------------------------------------------|-----------------------------------------------|
+| `Upsert(const GenericRow& row) -> Result`                   | Upsert a row 
(fire-and-forget)                |
+| `Upsert(const GenericRow& row, WriteResult& out) -> Result` | Upsert a row 
with write acknowledgment        |
+| `Delete(const GenericRow& row) -> Result`                   | Delete a row 
by primary key (fire-and-forget) |
+| `Delete(const GenericRow& row, WriteResult& out) -> Result` | Delete a row 
with write acknowledgment        |
+| `Flush() -> Result`                                         | Flush all 
pending operations                  |
+
+## `WriteResult`
+
+| Method             | Description                                 |
+|--------------------|---------------------------------------------|
+| `Wait() -> Result` | Wait for server acknowledgment of the write |
+
+## `Lookuper`
+
+| Method                                                                     | 
 Description                |
+|----------------------------------------------------------------------------|-----------------------------|
+| `Lookup(const GenericRow& pk_row, bool& found, GenericRow& out) -> Result` | 
Lookup a row by primary key |
+
+## `LogScanner`
+
+| Method                                                                       
                        |  Description                              |
+|------------------------------------------------------------------------------------------------------|-------------------------------------------|
+| `Subscribe(int32_t bucket_id, int64_t offset) -> Result`                     
                        | Subscribe to a single bucket at an offset |
+| `Subscribe(const std::vector<BucketSubscription>& bucket_offsets) -> Result` 
                        | Subscribe to multiple buckets             |
+| `SubscribePartitionBuckets(int64_t partition_id, int32_t bucket_id, int64_t 
start_offset) -> Result` | Subscribe to a single partition bucket    |
+| `SubscribePartitionBuckets(const std::vector<PartitionBucketSubscription>& 
subscriptions) -> Result` | Subscribe to multiple partition buckets   |
+| `Unsubscribe(int32_t bucket_id) -> Result`                                   
                        | Unsubscribe from a non-partitioned bucket |
+| `UnsubscribePartition(int64_t partition_id, int32_t bucket_id) -> Result`    
                        | Unsubscribe from a partition bucket       |
+| `Poll(int64_t timeout_ms, ScanRecords& out) -> Result`                       
                        | Poll individual records                   |
+| `PollRecordBatch(int64_t timeout_ms, ArrowRecordBatches& out) -> Result`     
                        | Poll Arrow RecordBatches                  |
+
+## `GenericRow`
+
+### Index-Based Getters
+
+| Method                                         |  Description                
   |
+|------------------------------------------------|--------------------------------|
+| `GetBool(size_t idx) -> bool`                  | Get boolean value at index  
   |
+| `GetInt32(size_t idx) -> int32_t`              | Get 32-bit integer at index 
   |
+| `GetInt64(size_t idx) -> int64_t`              | Get 64-bit integer at index 
   |
+| `GetFloat32(size_t idx) -> float`              | Get 32-bit float at index   
   |
+| `GetFloat64(size_t idx) -> double`             | Get 64-bit float at index   
   |
+| `GetString(size_t idx) -> std::string`         | Get string at index         
   |
+| `GetBytes(size_t idx) -> std::vector<uint8_t>` | Get binary data at index    
   |
+| `GetDate(size_t idx) -> Date`                  | Get date at index           
   |
+| `GetTime(size_t idx) -> Time`                  | Get time at index           
   |
+| `GetTimestamp(size_t idx) -> Timestamp`        | Get timestamp at index      
   |
+| `DecimalToString(size_t idx) -> std::string`   | Get decimal as string at 
index |
+
+### Index-Based Setters
+
+| Method                                                    |  Description     
              |
+|-----------------------------------------------------------|--------------------------------|
+| `SetNull(size_t idx)`                                     | Set field to 
null              |
+| `SetBool(size_t idx, bool value)`                         | Set boolean 
value              |
+| `SetInt32(size_t idx, int32_t value)`                     | Set 32-bit 
integer             |
+| `SetInt64(size_t idx, int64_t value)`                     | Set 64-bit 
integer             |
+| `SetFloat32(size_t idx, float value)`                     | Set 32-bit float 
              |
+| `SetFloat64(size_t idx, double value)`                    | Set 64-bit float 
              |
+| `SetString(size_t idx, const std::string& value)`         | Set string value 
              |
+| `SetBytes(size_t idx, const std::vector<uint8_t>& value)` | Set binary data  
              |
+| `SetDate(size_t idx, const Date& value)`                  | Set date value   
              |
+| `SetTime(size_t idx, const Time& value)`                  | Set time value   
              |
+| `SetTimestampNtz(size_t idx, const Timestamp& value)`     | Set timestamp 
without timezone |
+| `SetTimestampLtz(size_t idx, const Timestamp& value)`     | Set timestamp 
with timezone    |
+| `SetDecimal(size_t idx, const std::string& value)`        | Set decimal from 
string        |
+
+### Name-Based Setters
+
+When using `table.NewRow()`, the `Set()` method auto-routes to the correct 
type based on the schema:
+
+| Method                                                   |  Description      
                |
+|----------------------------------------------------------|-----------------------------------|
+| `Set(const std::string& name, bool value)`               | Set boolean by 
column name        |

Review Comment:
   nullptr overload is missing



##########
website/docs/user-guide/cpp/api-reference.md:
##########
@@ -0,0 +1,494 @@
+---
+sidebar_position: 2
+---
+# API Reference
+
+Complete API reference for the Fluss C++ client.
+
+## `Result`
+
+| Field / Method  | Type          | Description                                
                    |
+|-----------------|---------------|----------------------------------------------------------------|
+| `error_code`    | `int32_t`     | 0 for success, non-zero for errors         
                    |
+| `error_message` | `std::string` | Human-readable error description           
                    |
+| `Ok()`          | `bool`        | Returns `true` if operation succeeded 
(`error_code == 0`)      |
+
+## `Configuration`
+
+| Field                             | Type          | Default              | 
Description                                                     |
+|-----------------------------------|---------------|----------------------|-----------------------------------------------------------------|
+| `bootstrap_servers`               | `std::string` | `"127.0.0.1:9123"`   | 
Coordinator server address                                      |
+| `writer_request_max_size`         | `int32_t`     | `10485760` (10 MB)   | 
Maximum request size in bytes                                   |
+| `writer_acks`                     | `std::string` | `"all"`              | 
Acknowledgment setting (`"all"`, `"0"`, `"1"`, or `"-1"`)       |
+| `writer_retries`                  | `int32_t`     | `INT32_MAX`          | 
Number of retries on failure                                    |
+| `writer_batch_size`               | `int32_t`     | `2097152` (2 MB)     | 
Batch size for writes in bytes                                  |
+| `scanner_remote_log_prefetch_num` | `size_t`      | `4`                  | 
Number of remote log segments to prefetch                       |
+| `remote_file_download_thread_num` | `size_t`      | `3`                  | 
Number of threads for remote log downloads                      |
+
+## `Connection`
+
+| Method                                                                  | 
Description                                       |
+|-------------------------------------------------------------------------|---------------------------------------------------|
+| `static Create(const Configuration& config, Connection& out) -> Result` | 
Create a connection to a Fluss cluster            |
+| `GetAdmin(Admin& out) -> Result`                                        | 
Get the admin interface                           |
+| `GetTable(const TablePath& table_path, Table& out) -> Result`           | 
Get a table for read/write operations             |
+| `Available() -> bool`                                                   | 
Check if the connection is valid and initialized  |
+
+## `Admin`
+
+### Database Operations
+
+| Method                                                                       
                                             | Description              |
+|---------------------------------------------------------------------------------------------------------------------------|--------------------------|
+| `CreateDatabase(const std::string& database_name, const DatabaseDescriptor& 
descriptor, bool ignore_if_exists) -> Result` | Create a database        |
+| `DropDatabase(const std::string& name, bool ignore_if_not_exists, bool 
cascade) -> Result`                                | Drop a database          |
+| `ListDatabases(std::vector<std::string>& out) -> Result`                     
                                             | List all databases       |
+| `DatabaseExists(const std::string& name, bool& out) -> Result`               
                                             | Check if a database exists |
+| `GetDatabaseInfo(const std::string& name, DatabaseInfo& out) -> Result`      
                                             | Get database metadata    |
+
+### Table Operations
+
+| Method                                                                       
                              | Description                 |
+|------------------------------------------------------------------------------------------------------------|-----------------------------|
+| `CreateTable(const TablePath& path, const TableDescriptor& descriptor, bool 
ignore_if_exists) -> Result`   | Create a table              |
+| `DropTable(const TablePath& path, bool ignore_if_not_exists) -> Result`      
                              | Drop a table                |
+| `GetTableInfo(const TablePath& path, TableInfo& out) -> Result`              
                              | Get table metadata          |
+| `ListTables(const std::string& database_name, std::vector<std::string>& out) 
-> Result`                    | List tables in a database   |
+| `TableExists(const TablePath& path, bool& out) -> Result`                    
                              | Check if a table exists     |
+
+### Partition Operations
+
+| Method                                                                       
                                                                   | 
Description              |
+|-------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|
+| `CreatePartition(const TablePath& path, const 
std::unordered_map<std::string, std::string>& partition_spec, bool 
ignore_if_exists) -> Result`   | Create a partition       |
+| `DropPartition(const TablePath& path, const std::unordered_map<std::string, 
std::string>& partition_spec, bool ignore_if_not_exists) -> Result` | Drop a 
partition         |
+| `ListPartitionInfos(const TablePath& path, std::vector<PartitionInfo>& out) 
-> Result`                                                          | List 
partition metadata  |
+
+### Offset Operations
+
+| Method                                                                       
                                                                                
                                           | Description                        
     |
+|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|
+| `ListOffsets(const TablePath& path, const std::vector<int32_t>& bucket_ids, 
const OffsetQuery& query, std::unordered_map<int32_t, int64_t>& out) -> Result` 
                                            | Get offsets for buckets           
      |
+| `ListPartitionOffsets(const TablePath& path, const std::string& 
partition_name, const std::vector<int32_t>& bucket_ids, const OffsetQuery& 
query, std::unordered_map<int32_t, int64_t>& out) -> Result` | Get offsets for 
a partition's buckets   |
+
+### Lake Operations
+
+| Method                                                                      
| Description                  |
+|-----------------------------------------------------------------------------|------------------------------|
+| `GetLatestLakeSnapshot(const TablePath& path, LakeSnapshot& out) -> Result` 
| Get the latest lake snapshot |
+
+## `Table`
+
+| Method                        | Description                              |
+|-------------------------------|------------------------------------------|
+| `NewRow() -> GenericRow`      | Create a schema-aware row for this table |
+| `NewAppend() -> TableAppend`  | Create an append builder for log tables  |
+| `NewUpsert() -> TableUpsert`  | Create an upsert builder for PK tables   |
+| `NewLookup() -> TableLookup`  | Create a lookup builder for PK tables    |
+| `NewScan() -> TableScan`      | Create a scan builder                    |
+| `GetTableInfo() -> TableInfo` | Get table metadata                       |
+| `GetTablePath() -> TablePath` | Get the table path                       |
+| `HasPrimaryKey() -> bool`     | Check if the table has a primary key     |
+
+## `TableAppend`
+
+| Method                                       | Description             |
+|----------------------------------------------|-------------------------|
+| `CreateWriter(AppendWriter& out) -> Result`  | Create an append writer |
+
+## `TableUpsert`
+
+| Method                                                                       
| Description                                |
+|------------------------------------------------------------------------------|--------------------------------------------|
+| `PartialUpdateByIndex(std::vector<size_t> column_indices) -> TableUpsert&`   
| Configure partial update by column indices |
+| `PartialUpdateByName(std::vector<std::string> column_names) -> TableUpsert&` 
| Configure partial update by column names   |
+| `CreateWriter(UpsertWriter& out) -> Result`                                  
| Create an upsert writer                    |
+
+## `TableLookup`
+
+| Method                                    | Description                      
   |
+|-------------------------------------------|-------------------------------------|
+| `CreateLookuper(Lookuper& out) -> Result` | Create a lookuper for point 
lookups |
+
+## `TableScan`
+
+| Method                                                               | 
Description                                   |
+|----------------------------------------------------------------------|-----------------------------------------------|
+| `ProjectByIndex(std::vector<size_t> column_indices) -> TableScan&`   | 
Project columns by index                      |
+| `ProjectByName(std::vector<std::string> column_names) -> TableScan&` | 
Project columns by name                       |
+| `CreateLogScanner(LogScanner& out) -> Result`                        | 
Create a record-based log scanner             |
+| `CreateRecordBatchLogScanner(LogScanner& out) -> Result`             | 
Create an Arrow RecordBatch-based log scanner |
+
+## `AppendWriter`
+
+| Method                                                      | Description    
                        |
+|-------------------------------------------------------------|----------------------------------------|
+| `Append(const GenericRow& row) -> Result`                   | Append a row 
(fire-and-forget)         |
+| `Append(const GenericRow& row, WriteResult& out) -> Result` | Append a row 
with write acknowledgment |
+| `Flush() -> Result`                                         | Flush all 
pending writes               |
+
+## `UpsertWriter`
+
+| Method                                                      | Description    
                               |
+|-------------------------------------------------------------|-----------------------------------------------|
+| `Upsert(const GenericRow& row) -> Result`                   | Upsert a row 
(fire-and-forget)                |
+| `Upsert(const GenericRow& row, WriteResult& out) -> Result` | Upsert a row 
with write acknowledgment        |
+| `Delete(const GenericRow& row) -> Result`                   | Delete a row 
by primary key (fire-and-forget) |
+| `Delete(const GenericRow& row, WriteResult& out) -> Result` | Delete a row 
with write acknowledgment        |
+| `Flush() -> Result`                                         | Flush all 
pending operations                  |
+
+## `WriteResult`
+
+| Method             | Description                                 |
+|--------------------|---------------------------------------------|
+| `Wait() -> Result` | Wait for server acknowledgment of the write |
+
+## `Lookuper`
+
+| Method                                                                     | 
 Description                |
+|----------------------------------------------------------------------------|-----------------------------|
+| `Lookup(const GenericRow& pk_row, bool& found, GenericRow& out) -> Result` | 
Lookup a row by primary key |
+
+## `LogScanner`
+
+| Method                                                                       
                        |  Description                              |
+|------------------------------------------------------------------------------------------------------|-------------------------------------------|
+| `Subscribe(int32_t bucket_id, int64_t offset) -> Result`                     
                        | Subscribe to a single bucket at an offset |
+| `Subscribe(const std::vector<BucketSubscription>& bucket_offsets) -> Result` 
                        | Subscribe to multiple buckets             |
+| `SubscribePartitionBuckets(int64_t partition_id, int32_t bucket_id, int64_t 
start_offset) -> Result` | Subscribe to a single partition bucket    |
+| `SubscribePartitionBuckets(const std::vector<PartitionBucketSubscription>& 
subscriptions) -> Result` | Subscribe to multiple partition buckets   |
+| `Unsubscribe(int32_t bucket_id) -> Result`                                   
                        | Unsubscribe from a non-partitioned bucket |
+| `UnsubscribePartition(int64_t partition_id, int32_t bucket_id) -> Result`    
                        | Unsubscribe from a partition bucket       |
+| `Poll(int64_t timeout_ms, ScanRecords& out) -> Result`                       
                        | Poll individual records                   |
+| `PollRecordBatch(int64_t timeout_ms, ArrowRecordBatches& out) -> Result`     
                        | Poll Arrow RecordBatches                  |
+
+## `GenericRow`
+
+### Index-Based Getters
+
+| Method                                         |  Description                
   |
+|------------------------------------------------|--------------------------------|
+| `GetBool(size_t idx) -> bool`                  | Get boolean value at index  
   |
+| `GetInt32(size_t idx) -> int32_t`              | Get 32-bit integer at index 
   |
+| `GetInt64(size_t idx) -> int64_t`              | Get 64-bit integer at index 
   |
+| `GetFloat32(size_t idx) -> float`              | Get 32-bit float at index   
   |
+| `GetFloat64(size_t idx) -> double`             | Get 64-bit float at index   
   |
+| `GetString(size_t idx) -> std::string`         | Get string at index         
   |
+| `GetBytes(size_t idx) -> std::vector<uint8_t>` | Get binary data at index    
   |
+| `GetDate(size_t idx) -> Date`                  | Get date at index           
   |
+| `GetTime(size_t idx) -> Time`                  | Get time at index           
   |
+| `GetTimestamp(size_t idx) -> Timestamp`        | Get timestamp at index      
   |
+| `DecimalToString(size_t idx) -> std::string`   | Get decimal as string at 
index |
+
+### Index-Based Setters
+
+| Method                                                    |  Description     
              |
+|-----------------------------------------------------------|--------------------------------|
+| `SetNull(size_t idx)`                                     | Set field to 
null              |
+| `SetBool(size_t idx, bool value)`                         | Set boolean 
value              |
+| `SetInt32(size_t idx, int32_t value)`                     | Set 32-bit 
integer             |
+| `SetInt64(size_t idx, int64_t value)`                     | Set 64-bit 
integer             |
+| `SetFloat32(size_t idx, float value)`                     | Set 32-bit float 
              |
+| `SetFloat64(size_t idx, double value)`                    | Set 64-bit float 
              |
+| `SetString(size_t idx, const std::string& value)`         | Set string value 
              |
+| `SetBytes(size_t idx, const std::vector<uint8_t>& value)` | Set binary data  
              |
+| `SetDate(size_t idx, const Date& value)`                  | Set date value   
              |
+| `SetTime(size_t idx, const Time& value)`                  | Set time value   
              |
+| `SetTimestampNtz(size_t idx, const Timestamp& value)`     | Set timestamp 
without timezone |
+| `SetTimestampLtz(size_t idx, const Timestamp& value)`     | Set timestamp 
with timezone    |
+| `SetDecimal(size_t idx, const std::string& value)`        | Set decimal from 
string        |
+
+### Name-Based Setters
+
+When using `table.NewRow()`, the `Set()` method auto-routes to the correct 
type based on the schema:
+
+| Method                                                   |  Description      
                |
+|----------------------------------------------------------|-----------------------------------|
+| `Set(const std::string& name, bool value)`               | Set boolean by 
column name        |
+| `Set(const std::string& name, int32_t value)`            | Set integer by 
column name        |
+| `Set(const std::string& name, int64_t value)`            | Set big integer 
by column name    |
+| `Set(const std::string& name, float value)`              | Set float by 
column name          |
+| `Set(const std::string& name, double value)`             | Set double by 
column name         |
+| `Set(const std::string& name, const std::string& value)` | Set 
string/decimal by column name |
+| `Set(const std::string& name, const Date& value)`        | Set date by 
column name           |
+| `Set(const std::string& name, const Time& value)`        | Set time by 
column name           |
+| `Set(const std::string& name, const Timestamp& value)`   | Set timestamp by 
column name      |
+
+### Row Inspection
+
+| Method                             |  Description                     |
+|------------------------------------|----------------------------------|
+| `FieldCount() -> size_t`           | Get the number of fields         |
+| `GetType(size_t idx) -> DatumType` | Get the datum type at index      |
+| `IsNull(size_t idx) -> bool`       | Check if field is null           |
+| `IsDecimal(size_t idx) -> bool`    | Check if field is a decimal type |
+
+## `ScanRecord`
+
+| Field       | Type         |  Description                  |
+|-------------|--------------|-------------------------------|
+| `bucket_id` | `int32_t`    | Bucket this record belongs to |
+| `offset`    | `int64_t`    | Record offset in the log      |
+| `timestamp` | `int64_t`    | Record timestamp              |
+| `row`       | `GenericRow` | Row data                      |
+
+## `ScanRecords`
+
+| Method                                        |  Description                 
              |
+|-----------------------------------------------|--------------------------------------------|
+| `Size() -> size_t`                            | Number of records            
              |
+| `Empty() -> bool`                             | Check if empty               
              |
+| `operator[](size_t idx) -> const ScanRecord&` | Access record by index       
              |
+| `begin() / end()`                             | Iterator support for 
range-based for loops |
+
+## `ArrowRecordBatch`
+
+| Method                                                         |  
Description                         |
+|----------------------------------------------------------------|--------------------------------------|
+| `GetArrowRecordBatch() -> std::shared_ptr<arrow::RecordBatch>` | Get the 
underlying Arrow RecordBatch |
+| `NumRows() -> int64_t`                                         | Number of 
rows in the batch          |
+| `GetTableId() -> int64_t`                                      | Table ID    
                         |
+| `GetPartitionId() -> int64_t`                                  | Partition 
ID                         |
+| `GetBucketId() -> int32_t`                                     | Bucket ID   
                         |
+| `GetBaseOffset() -> int64_t`                                   | First 
record offset                  |
+| `GetLastOffset() -> int64_t`                                   | Last record 
offset                   |
+
+## `ArrowRecordBatches`
+
+| Method                   |  Description                               |
+|--------------------------|--------------------------------------------|
+| `Size() -> size_t`       | Number of batches                          |
+| `Empty() -> bool`        | Check if empty                             |
+| `operator[](size_t idx)` | Access batch by index                      |
+| `begin() / end()`        | Iterator support for range-based for loops |
+
+## `Schema`
+
+| Method                            |  Description                |
+|-----------------------------------|-----------------------------|
+| `NewBuilder() -> Schema::Builder` | Create a new schema builder |
+
+## `Schema::Builder`
+
+| Method                                                                 |  
Description            |
+|------------------------------------------------------------------------|-------------------------|
+| `AddColumn(const std::string& name, const DataType& type) -> Builder&` | Add 
a column            |
+| `SetPrimaryKeys(const std::vector<std::string>& keys) -> Builder&`     | Set 
primary key columns |
+| `Build() -> Schema`                                                    | 
Build the schema        |
+
+## `TableDescriptor`
+
+| Method                                     |  Description                    
      |
+|--------------------------------------------|---------------------------------------|
+| `NewBuilder() -> TableDescriptor::Builder` | Create a new table descriptor 
builder |
+
+## `TableDescriptor::Builder`
+
+| Method                                                                      
|  Description               |
+|-----------------------------------------------------------------------------|----------------------------|
+| `SetSchema(const Schema& schema) -> Builder&`                               
| Set the table schema       |
+| `SetPartitionKeys(const std::vector<std::string>& keys) -> Builder&`        
| Set partition key columns  |
+| `SetBucketCount(int32_t count) -> Builder&`                                 
| Set the number of buckets  |
+| `SetBucketKeys(const std::vector<std::string>& keys) -> Builder&`           
| Set bucket key columns     |
+| `SetProperty(const std::string& key, const std::string& value) -> Builder&` 
| Set a table property       |
+| `SetComment(const std::string& comment) -> Builder&`                        
| Set a table comment        |
+| `Build() -> TableDescriptor`                                                
| Build the table descriptor |
+
+## `DataType`
+
+### Factory Methods
+
+| Method                                        |  Description                 
      |
+|-----------------------------------------------|------------------------------------|
+| `DataType::Boolean()`                         | Boolean type                 
      |
+| `DataType::TinyInt()`                         | 8-bit signed integer         
      |
+| `DataType::SmallInt()`                        | 16-bit signed integer        
      |
+| `DataType::Int()`                             | 32-bit signed integer        
      |
+| `DataType::BigInt()`                          | 64-bit signed integer        
      |
+| `DataType::Float()`                           | 32-bit floating point        
      |
+| `DataType::Double()`                          | 64-bit floating point        
      |
+| `DataType::String()`                          | UTF-8 string                 
      |
+| `DataType::Bytes()`                           | Binary data                  
      |
+| `DataType::Date()`                            | Date (days since epoch)      
      |
+| `DataType::Time()`                            | Time (milliseconds since 
midnight) |
+| `DataType::Timestamp(int precision)`          | Timestamp without timezone   
      |
+| `DataType::TimestampLtz(int precision)`       | Timestamp with timezone      
      |
+| `DataType::Decimal(int precision, int scale)` | Decimal with precision and 
scale   |
+
+### Accessors
+
+| Method               |  Description                                |
+|----------------------|---------------------------------------------|
+| `id() -> TypeId`     | Get the type ID                             |
+| `precision() -> int` | Get precision (for Decimal/Timestamp types) |
+| `scale() -> int`     | Get scale (for Decimal type)                |
+
+## `TablePath`
+
+| Method / Field                                                     |  
Description          |
+|--------------------------------------------------------------------|-----------------------|
+| `TablePath(const std::string& database, const std::string& table)` | Create 
a table path   |
+| `database_name -> std::string`                                     | 
Database name         |
+| `table_name -> std::string`                                        | Table 
name            |
+| `ToString() -> std::string`                                        | String 
representation |
+
+## `TableInfo`
+
+| Field             | Type                                           |  
Description                        |
+|-------------------|------------------------------------------------|-------------------------------------|
+| `table_id`        | `int64_t`                                      | Table 
ID                            |
+| `schema_id`       | `int32_t`                                      | Schema 
ID                           |
+| `table_path`      | `TablePath`                                    | Table 
path                          |
+| `created_time`    | `int64_t`                                      | 
Creation timestamp                  |
+| `modified_time`   | `int64_t`                                      | Last 
modification timestamp         |
+| `primary_keys`    | `std::vector<std::string>`                     | Primary 
key columns                 |
+| `bucket_keys`     | `std::vector<std::string>`                     | Bucket 
key columns                  |
+| `partition_keys`  | `std::vector<std::string>`                     | 
Partition key columns               |
+| `num_buckets`     | `int32_t`                                      | Number 
of buckets                   |
+| `has_primary_key` | `bool`                                         | Whether 
the table has a primary key |
+| `is_partitioned`  | `bool`                                         | Whether 
the table is partitioned    |
+| `properties`      | `std::unordered_map<std::string, std::string>` | Table 
properties                    |
+| `comment`         | `std::string`                                  | Table 
comment                       |
+| `schema`          | `Schema`                                       | Table 
schema                        |
+
+## Temporal Types
+
+### `Date`
+
+| Method                                        |  Description                 
|
+|-----------------------------------------------|------------------------------|
+| `Date::FromDays(int32_t days)`                | Create from days since epoch 
|
+| `Date::FromYMD(int year, int month, int day)` | Create from year, month, day 
|
+| `Year() -> int`                               | Get year                     
|
+| `Month() -> int`                              | Get month                    
|
+| `Day() -> int`                                | Get day                      
|
+
+### `Time`
+
+| Method                                            |  Description             
                    |
+|---------------------------------------------------|----------------------------------------------|
+| `Time::FromMillis(int32_t millis)`                | Create from milliseconds 
since midnight      |
+| `Time::FromHMS(int hour, int minute, int second)` | Create from hour, 
minute, second             |
+| `Hour() -> int`                                   | Get hour                 
                    |
+| `Minute() -> int`                                 | Get minute               
                    |
+| `Second() -> int`                                 | Get second               
                    |
+| `Millis() -> int64_t`                             | Get sub-second 
millisecond component (0-999) |
+
+### `Timestamp`
+
+| Method                                                               |  
Description                             |
+|----------------------------------------------------------------------|------------------------------------------|
+| `Timestamp::FromMillis(int64_t millis)`                              | 
Create from milliseconds since epoch     |
+| `Timestamp::FromMillisNanos(int64_t millis, int32_t nanos)`          | 
Create from milliseconds and nanoseconds |
+| `Timestamp::FromTimePoint(std::chrono::system_clock::time_point tp)` | 
Create from a time point                 |
+
+## `PartitionInfo`
+
+| Field            | Type          |  Description   |
+|------------------|---------------|----------------|
+| `partition_id`   | `int64_t`     | Partition ID   |
+| `partition_name` | `std::string` | Partition name |
+
+## `DatabaseDescriptor`
+
+| Field        | Type                                           | Description  
     |
+|--------------|------------------------------------------------|-------------------|
+| `comment`    | `std::string`                                  | Database 
comment  |
+| `properties` | `std::unordered_map<std::string, std::string>` | Custom 
properties |
+
+## `DatabaseInfo`
+
+| Field           | Type                                           |  
Description                |
+|-----------------|------------------------------------------------|-----------------------------|
+| `database_name` | `std::string`                                  | Database 
name               |
+| `comment`       | `std::string`                                  | Database 
comment            |
+| `properties`    | `std::unordered_map<std::string, std::string>` | Custom 
properties           |
+| `created_time`  | `int64_t`                                      | Creation 
timestamp          |
+| `modified_time` | `int64_t`                                      | Last 
modification timestamp |
+
+## `LakeSnapshot`
+
+| Field            | Type                        |  Description       |
+|------------------|-----------------------------|--------------------|
+| `snapshot_id`    | `int64_t`                   | Snapshot ID        |
+| `bucket_offsets` | `std::vector<BucketOffset>` | All bucket offsets |
+
+## `BucketOffset`
+
+| Field          | Type      | Description  |
+|----------------|-----------|--------------|
+| `table_id`     | `int64_t` | Table ID     |
+| `partition_id` | `int64_t` | Partition ID |
+| `bucket_id`    | `int32_t` | Bucket ID    |
+| `offset`       | `int64_t` | Offset value |
+
+## `OffsetQuery`
+
+| Method                                             | Description             
                |
+|----------------------------------------------------|-----------------------------------------|
+| `OffsetQuery::Earliest()`                          | Query for the earliest 
available offset |

Review Comment:
   I think we have inconsistent names between 3 clients: OffsetSpec, 
OffsetType, OffsetQuery. 
   We need to fix it in code



##########
website/docs/user-guide/rust/example/admin-operations.md:
##########
@@ -0,0 +1,118 @@
+---
+sidebar_position: 3
+---
+# Admin Operations
+
+## Get Admin Interface
+
+```rust
+let admin = conn.get_admin().await?;
+```
+
+## Database Operations
+
+```rust
+// Create database
+admin.create_database("my_database", None, true).await?;
+
+// List all databases
+let databases = admin.list_databases().await?;
+println!("Databases: {:?}", databases);
+
+// Check if database exists
+let exists = admin.database_exists("my_database").await?;
+
+// Get database information
+let db_info = admin.get_database_info("my_database").await?;
+
+// Drop database
+admin.drop_database("my_database", true, false).await?;
+```
+
+## Table Operations
+
+```rust
+use fluss::metadata::{DataTypes, Schema, TableDescriptor, TablePath};
+
+let table_descriptor = TableDescriptor::builder()
+    .schema(
+        Schema::builder()
+            .column("id", DataTypes::int())
+            .column("name", DataTypes::string())
+            .column("amount", DataTypes::bigint())
+            .build()?,
+    )
+    .build()?;
+
+let table_path = TablePath::new("my_database", "my_table");
+
+// Create table
+admin.create_table(&table_path, &table_descriptor, true).await?;
+
+// Get table information
+let table_info = admin.get_table_info(&table_path).await?;
+println!("Table: {}", table_info);
+
+// List tables in database
+let tables = admin.list_tables("my_database").await?;
+
+// Check if table exists
+let exists = admin.table_exists(&table_path).await?;
+
+// Drop table
+admin.drop_table(&table_path, true).await?;
+```
+
+## Partition Operations
+
+```rust
+use fluss::metadata::PartitionSpec;
+use std::collections::HashMap;
+
+// List all partitions
+let partitions = admin.list_partition_infos(&table_path).await?;
+
+// List partitions matching a spec
+let mut filter = HashMap::new();
+filter.insert("year", "2024");
+let spec = PartitionSpec::new(filter);
+let partitions = admin.list_partition_infos_with_spec(&table_path, 
Some(&spec)).await?;

Review Comment:
   I don't see the method in API reference



##########
website/docs/user-guide/cpp/data-types.md:
##########
@@ -0,0 +1,109 @@
+---
+sidebar_position: 3
+---
+# Data Types
+
+## Schema DataTypes
+
+| DataType                   | Description                        |
+|----------------------------|------------------------------------|
+| `DataType::Boolean()`      | Boolean value                      |
+| `DataType::TinyInt()`      | 8-bit signed integer               |
+| `DataType::SmallInt()`     | 16-bit signed integer              |
+| `DataType::Int()`          | 32-bit signed integer              |
+| `DataType::BigInt()`       | 64-bit signed integer              |
+| `DataType::Float()`        | 32-bit floating point              |
+| `DataType::Double()`       | 64-bit floating point              |
+| `DataType::String()`       | UTF-8 string                       |
+| `DataType::Bytes()`        | Binary data                        |
+| `DataType::Date()`         | Date (days since epoch)            |
+| `DataType::Time()`         | Time (milliseconds since midnight) |
+| `DataType::Timestamp()`    | Timestamp without timezone         |
+| `DataType::TimestampLtz()` | Timestamp with timezone            |
+| `DataType::Decimal(p, s)`  | Decimal with precision and scale   |
+
+## GenericRow Setters
+
+```cpp
+fluss::GenericRow row;
+row.SetNull(0);
+row.SetBool(1, true);
+row.SetInt32(2, 42);
+row.SetInt64(3, 1234567890L);
+row.SetFloat32(4, 3.14f);
+row.SetFloat64(5, 2.71828);
+row.SetString(6, "hello");
+row.SetBytes(7, {0x01, 0x02, 0x03});
+```
+
+## Name-Based Setters
+
+When using `table.NewRow()`, you can set fields by column name. The setter 
automatically routes to the correct type based on the schema:
+
+```cpp
+auto row = table.NewRow();
+row.Set("user_id", 1);
+row.Set("name", "Alice");
+row.Set("score", 95.5f);
+row.Set("balance", "1234.56");   // decimal as string
+row.Set("birth_date", fluss::Date::FromYMD(1990, 3, 15));
+row.Set("login_time", fluss::Time::FromHMS(9, 30, 0));
+row.Set("created_at", fluss::Timestamp::FromMillis(1700000000000));

Review Comment:
   We need to mention how to create null values: `row.Set("email", nullptr);`



##########
website/docs/user-guide/cpp/api-reference.md:
##########
@@ -0,0 +1,494 @@
+---
+sidebar_position: 2
+---
+# API Reference
+
+Complete API reference for the Fluss C++ client.
+
+## `Result`
+
+| Field / Method  | Type          | Description                                
                    |
+|-----------------|---------------|----------------------------------------------------------------|
+| `error_code`    | `int32_t`     | 0 for success, non-zero for errors         
                    |
+| `error_message` | `std::string` | Human-readable error description           
                    |
+| `Ok()`          | `bool`        | Returns `true` if operation succeeded 
(`error_code == 0`)      |
+
+## `Configuration`
+
+| Field                             | Type          | Default              | 
Description                                                     |
+|-----------------------------------|---------------|----------------------|-----------------------------------------------------------------|
+| `bootstrap_servers`               | `std::string` | `"127.0.0.1:9123"`   | 
Coordinator server address                                      |
+| `writer_request_max_size`         | `int32_t`     | `10485760` (10 MB)   | 
Maximum request size in bytes                                   |
+| `writer_acks`                     | `std::string` | `"all"`              | 
Acknowledgment setting (`"all"`, `"0"`, `"1"`, or `"-1"`)       |
+| `writer_retries`                  | `int32_t`     | `INT32_MAX`          | 
Number of retries on failure                                    |
+| `writer_batch_size`               | `int32_t`     | `2097152` (2 MB)     | 
Batch size for writes in bytes                                  |
+| `scanner_remote_log_prefetch_num` | `size_t`      | `4`                  | 
Number of remote log segments to prefetch                       |
+| `remote_file_download_thread_num` | `size_t`      | `3`                  | 
Number of threads for remote log downloads                      |
+
+## `Connection`
+
+| Method                                                                  | 
Description                                       |
+|-------------------------------------------------------------------------|---------------------------------------------------|
+| `static Create(const Configuration& config, Connection& out) -> Result` | 
Create a connection to a Fluss cluster            |
+| `GetAdmin(Admin& out) -> Result`                                        | 
Get the admin interface                           |
+| `GetTable(const TablePath& table_path, Table& out) -> Result`           | 
Get a table for read/write operations             |
+| `Available() -> bool`                                                   | 
Check if the connection is valid and initialized  |
+
+## `Admin`
+
+### Database Operations
+
+| Method                                                                       
                                             | Description              |
+|---------------------------------------------------------------------------------------------------------------------------|--------------------------|
+| `CreateDatabase(const std::string& database_name, const DatabaseDescriptor& 
descriptor, bool ignore_if_exists) -> Result` | Create a database        |
+| `DropDatabase(const std::string& name, bool ignore_if_not_exists, bool 
cascade) -> Result`                                | Drop a database          |
+| `ListDatabases(std::vector<std::string>& out) -> Result`                     
                                             | List all databases       |
+| `DatabaseExists(const std::string& name, bool& out) -> Result`               
                                             | Check if a database exists |
+| `GetDatabaseInfo(const std::string& name, DatabaseInfo& out) -> Result`      
                                             | Get database metadata    |
+
+### Table Operations
+
+| Method                                                                       
                              | Description                 |
+|------------------------------------------------------------------------------------------------------------|-----------------------------|
+| `CreateTable(const TablePath& path, const TableDescriptor& descriptor, bool 
ignore_if_exists) -> Result`   | Create a table              |
+| `DropTable(const TablePath& path, bool ignore_if_not_exists) -> Result`      
                              | Drop a table                |
+| `GetTableInfo(const TablePath& path, TableInfo& out) -> Result`              
                              | Get table metadata          |
+| `ListTables(const std::string& database_name, std::vector<std::string>& out) 
-> Result`                    | List tables in a database   |
+| `TableExists(const TablePath& path, bool& out) -> Result`                    
                              | Check if a table exists     |
+
+### Partition Operations
+
+| Method                                                                       
                                                                   | 
Description              |
+|-------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------|
+| `CreatePartition(const TablePath& path, const 
std::unordered_map<std::string, std::string>& partition_spec, bool 
ignore_if_exists) -> Result`   | Create a partition       |
+| `DropPartition(const TablePath& path, const std::unordered_map<std::string, 
std::string>& partition_spec, bool ignore_if_not_exists) -> Result` | Drop a 
partition         |
+| `ListPartitionInfos(const TablePath& path, std::vector<PartitionInfo>& out) 
-> Result`                                                          | List 
partition metadata  |
+
+### Offset Operations
+
+| Method                                                                       
                                                                                
                                           | Description                        
     |
+|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|
+| `ListOffsets(const TablePath& path, const std::vector<int32_t>& bucket_ids, 
const OffsetQuery& query, std::unordered_map<int32_t, int64_t>& out) -> Result` 
                                            | Get offsets for buckets           
      |
+| `ListPartitionOffsets(const TablePath& path, const std::string& 
partition_name, const std::vector<int32_t>& bucket_ids, const OffsetQuery& 
query, std::unordered_map<int32_t, int64_t>& out) -> Result` | Get offsets for 
a partition's buckets   |
+
+### Lake Operations
+
+| Method                                                                      
| Description                  |
+|-----------------------------------------------------------------------------|------------------------------|
+| `GetLatestLakeSnapshot(const TablePath& path, LakeSnapshot& out) -> Result` 
| Get the latest lake snapshot |
+
+## `Table`
+
+| Method                        | Description                              |
+|-------------------------------|------------------------------------------|
+| `NewRow() -> GenericRow`      | Create a schema-aware row for this table |
+| `NewAppend() -> TableAppend`  | Create an append builder for log tables  |
+| `NewUpsert() -> TableUpsert`  | Create an upsert builder for PK tables   |
+| `NewLookup() -> TableLookup`  | Create a lookup builder for PK tables    |
+| `NewScan() -> TableScan`      | Create a scan builder                    |
+| `GetTableInfo() -> TableInfo` | Get table metadata                       |
+| `GetTablePath() -> TablePath` | Get the table path                       |
+| `HasPrimaryKey() -> bool`     | Check if the table has a primary key     |
+
+## `TableAppend`
+
+| Method                                       | Description             |
+|----------------------------------------------|-------------------------|
+| `CreateWriter(AppendWriter& out) -> Result`  | Create an append writer |
+
+## `TableUpsert`
+
+| Method                                                                       
| Description                                |
+|------------------------------------------------------------------------------|--------------------------------------------|
+| `PartialUpdateByIndex(std::vector<size_t> column_indices) -> TableUpsert&`   
| Configure partial update by column indices |
+| `PartialUpdateByName(std::vector<std::string> column_names) -> TableUpsert&` 
| Configure partial update by column names   |
+| `CreateWriter(UpsertWriter& out) -> Result`                                  
| Create an upsert writer                    |
+
+## `TableLookup`
+
+| Method                                    | Description                      
   |
+|-------------------------------------------|-------------------------------------|
+| `CreateLookuper(Lookuper& out) -> Result` | Create a lookuper for point 
lookups |
+
+## `TableScan`
+
+| Method                                                               | 
Description                                   |
+|----------------------------------------------------------------------|-----------------------------------------------|
+| `ProjectByIndex(std::vector<size_t> column_indices) -> TableScan&`   | 
Project columns by index                      |
+| `ProjectByName(std::vector<std::string> column_names) -> TableScan&` | 
Project columns by name                       |
+| `CreateLogScanner(LogScanner& out) -> Result`                        | 
Create a record-based log scanner             |
+| `CreateRecordBatchLogScanner(LogScanner& out) -> Result`             | 
Create an Arrow RecordBatch-based log scanner |
+
+## `AppendWriter`
+
+| Method                                                      | Description    
                        |
+|-------------------------------------------------------------|----------------------------------------|
+| `Append(const GenericRow& row) -> Result`                   | Append a row 
(fire-and-forget)         |
+| `Append(const GenericRow& row, WriteResult& out) -> Result` | Append a row 
with write acknowledgment |
+| `Flush() -> Result`                                         | Flush all 
pending writes               |
+
+## `UpsertWriter`
+
+| Method                                                      | Description    
                               |
+|-------------------------------------------------------------|-----------------------------------------------|
+| `Upsert(const GenericRow& row) -> Result`                   | Upsert a row 
(fire-and-forget)                |
+| `Upsert(const GenericRow& row, WriteResult& out) -> Result` | Upsert a row 
with write acknowledgment        |
+| `Delete(const GenericRow& row) -> Result`                   | Delete a row 
by primary key (fire-and-forget) |
+| `Delete(const GenericRow& row, WriteResult& out) -> Result` | Delete a row 
with write acknowledgment        |
+| `Flush() -> Result`                                         | Flush all 
pending operations                  |
+
+## `WriteResult`
+
+| Method             | Description                                 |
+|--------------------|---------------------------------------------|
+| `Wait() -> Result` | Wait for server acknowledgment of the write |
+
+## `Lookuper`
+
+| Method                                                                     | 
 Description                |
+|----------------------------------------------------------------------------|-----------------------------|
+| `Lookup(const GenericRow& pk_row, bool& found, GenericRow& out) -> Result` | 
Lookup a row by primary key |
+
+## `LogScanner`
+
+| Method                                                                       
                        |  Description                              |
+|------------------------------------------------------------------------------------------------------|-------------------------------------------|
+| `Subscribe(int32_t bucket_id, int64_t offset) -> Result`                     
                        | Subscribe to a single bucket at an offset |
+| `Subscribe(const std::vector<BucketSubscription>& bucket_offsets) -> Result` 
                        | Subscribe to multiple buckets             |
+| `SubscribePartitionBuckets(int64_t partition_id, int32_t bucket_id, int64_t 
start_offset) -> Result` | Subscribe to a single partition bucket    |
+| `SubscribePartitionBuckets(const std::vector<PartitionBucketSubscription>& 
subscriptions) -> Result` | Subscribe to multiple partition buckets   |
+| `Unsubscribe(int32_t bucket_id) -> Result`                                   
                        | Unsubscribe from a non-partitioned bucket |
+| `UnsubscribePartition(int64_t partition_id, int32_t bucket_id) -> Result`    
                        | Unsubscribe from a partition bucket       |
+| `Poll(int64_t timeout_ms, ScanRecords& out) -> Result`                       
                        | Poll individual records                   |
+| `PollRecordBatch(int64_t timeout_ms, ArrowRecordBatches& out) -> Result`     
                        | Poll Arrow RecordBatches                  |
+
+## `GenericRow`
+
+### Index-Based Getters
+
+| Method                                         |  Description                
   |
+|------------------------------------------------|--------------------------------|
+| `GetBool(size_t idx) -> bool`                  | Get boolean value at index  
   |
+| `GetInt32(size_t idx) -> int32_t`              | Get 32-bit integer at index 
   |
+| `GetInt64(size_t idx) -> int64_t`              | Get 64-bit integer at index 
   |
+| `GetFloat32(size_t idx) -> float`              | Get 32-bit float at index   
   |
+| `GetFloat64(size_t idx) -> double`             | Get 64-bit float at index   
   |
+| `GetString(size_t idx) -> std::string`         | Get string at index         
   |
+| `GetBytes(size_t idx) -> std::vector<uint8_t>` | Get binary data at index    
   |
+| `GetDate(size_t idx) -> Date`                  | Get date at index           
   |
+| `GetTime(size_t idx) -> Time`                  | Get time at index           
   |
+| `GetTimestamp(size_t idx) -> Timestamp`        | Get timestamp at index      
   |
+| `DecimalToString(size_t idx) -> std::string`   | Get decimal as string at 
index |
+
+### Index-Based Setters
+
+| Method                                                    |  Description     
              |
+|-----------------------------------------------------------|--------------------------------|
+| `SetNull(size_t idx)`                                     | Set field to 
null              |
+| `SetBool(size_t idx, bool value)`                         | Set boolean 
value              |
+| `SetInt32(size_t idx, int32_t value)`                     | Set 32-bit 
integer             |
+| `SetInt64(size_t idx, int64_t value)`                     | Set 64-bit 
integer             |
+| `SetFloat32(size_t idx, float value)`                     | Set 32-bit float 
              |
+| `SetFloat64(size_t idx, double value)`                    | Set 64-bit float 
              |
+| `SetString(size_t idx, const std::string& value)`         | Set string value 
              |
+| `SetBytes(size_t idx, const std::vector<uint8_t>& value)` | Set binary data  
              |
+| `SetDate(size_t idx, const Date& value)`                  | Set date value   
              |
+| `SetTime(size_t idx, const Time& value)`                  | Set time value   
              |
+| `SetTimestampNtz(size_t idx, const Timestamp& value)`     | Set timestamp 
without timezone |
+| `SetTimestampLtz(size_t idx, const Timestamp& value)`     | Set timestamp 
with timezone    |
+| `SetDecimal(size_t idx, const std::string& value)`        | Set decimal from 
string        |
+
+### Name-Based Setters
+
+When using `table.NewRow()`, the `Set()` method auto-routes to the correct 
type based on the schema:
+
+| Method                                                   |  Description      
                |
+|----------------------------------------------------------|-----------------------------------|
+| `Set(const std::string& name, bool value)`               | Set boolean by 
column name        |
+| `Set(const std::string& name, int32_t value)`            | Set integer by 
column name        |
+| `Set(const std::string& name, int64_t value)`            | Set big integer 
by column name    |
+| `Set(const std::string& name, float value)`              | Set float by 
column name          |
+| `Set(const std::string& name, double value)`             | Set double by 
column name         |
+| `Set(const std::string& name, const std::string& value)` | Set 
string/decimal by column name |
+| `Set(const std::string& name, const Date& value)`        | Set date by 
column name           |
+| `Set(const std::string& name, const Time& value)`        | Set time by 
column name           |
+| `Set(const std::string& name, const Timestamp& value)`   | Set timestamp by 
column name      |
+
+### Row Inspection
+
+| Method                             |  Description                     |
+|------------------------------------|----------------------------------|
+| `FieldCount() -> size_t`           | Get the number of fields         |
+| `GetType(size_t idx) -> DatumType` | Get the datum type at index      |
+| `IsNull(size_t idx) -> bool`       | Check if field is null           |
+| `IsDecimal(size_t idx) -> bool`    | Check if field is a decimal type |
+
+## `ScanRecord`
+
+| Field       | Type         |  Description                  |
+|-------------|--------------|-------------------------------|
+| `bucket_id` | `int32_t`    | Bucket this record belongs to |
+| `offset`    | `int64_t`    | Record offset in the log      |
+| `timestamp` | `int64_t`    | Record timestamp              |
+| `row`       | `GenericRow` | Row data                      |
+
+## `ScanRecords`
+
+| Method                                        |  Description                 
              |
+|-----------------------------------------------|--------------------------------------------|
+| `Size() -> size_t`                            | Number of records            
              |
+| `Empty() -> bool`                             | Check if empty               
              |
+| `operator[](size_t idx) -> const ScanRecord&` | Access record by index       
              |
+| `begin() / end()`                             | Iterator support for 
range-based for loops |
+
+## `ArrowRecordBatch`
+
+| Method                                                         |  
Description                         |
+|----------------------------------------------------------------|--------------------------------------|
+| `GetArrowRecordBatch() -> std::shared_ptr<arrow::RecordBatch>` | Get the 
underlying Arrow RecordBatch |

Review Comment:
   Available()? we use it in the example, so weird to lack it here



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to