This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new 1dab4960 feat: rust examples for creating and querying Paimon tables 
(#648)
1dab4960 is described below

commit 1dab496083ae44de8bdbd2ac4614b2477450f38a
Author: Ganesh Sivakumar <[email protected]>
AuthorDate: Sat Aug 15 13:47:07 2026 +0530

    feat: rust examples for creating and querying Paimon tables (#648)
---
 Cargo.toml                                         |  10 +-
 .../datafusion/examples/datafusion_query.rs        |  85 +++++++++++++
 crates/paimon/Cargo.toml                           |  13 +-
 crates/paimon/examples/create_table.rs             | 134 +++++++++++++++++++++
 4 files changed, 239 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index fab0a8db..08fe20d3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,7 +17,15 @@
 
 [workspace]
 resolver = "2"
-members = ["crates/paimon", "crates/paimon-rest-server", 
"crates/integration_tests", "bindings/c", "bindings/python", 
"crates/integrations/datafusion", "benchmarks/tpcds"]
+members = [
+    "crates/paimon",
+    "crates/paimon-rest-server",
+    "crates/integration_tests",
+    "bindings/c",
+    "bindings/python",
+    "crates/integrations/datafusion",
+    "benchmarks/tpcds",
+]
 
 [workspace.package]
 version = "0.4.0"
diff --git a/crates/integrations/datafusion/examples/datafusion_query.rs 
b/crates/integrations/datafusion/examples/datafusion_query.rs
new file mode 100644
index 00000000..b3873a00
--- /dev/null
+++ b/crates/integrations/datafusion/examples/datafusion_query.rs
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::error::Error;
+use std::sync::Arc;
+
+use datafusion::prelude::{col, lit, SessionContext};
+use paimon::catalog::Identifier;
+use paimon::{Catalog, CatalogFactory, CatalogOptions, Options};
+use paimon_datafusion::PaimonTableProvider;
+
+// This example demonstrates how to query a Paimon table
+// using the DataFusion DataFrame API.
+//
+// Before running this example, create the sample table at
+// examples/create_table, then pass the catalog warehouse path:
+// cargo run --package paimon-datafusion --example datafusion_query -- 
/path/to/warehouse
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn Error>> {
+    let warehouse = std::env::args().nth(1).ok_or_else(|| {
+        std::io::Error::new(
+            std::io::ErrorKind::InvalidInput,
+            "usage: cargo run --package paimon-datafusion --example 
datafusion_query -- <warehouse-path>",
+        )
+    })?;
+
+    // Open the local Paimon catalog
+    let catalog = create_catalog(warehouse).await?;
+
+    // Load the users table
+    let identifier = Identifier::new("my_db", "users");
+    let table = catalog.get_table(&identifier).await?;
+
+    // DataFusion TableProvider for the Paimon table
+    let provider = PaimonTableProvider::try_new(table)?;
+
+    let ctx = SessionContext::new();
+
+    // Register table
+    ctx.register_table("user_table", Arc::new(provider))?;
+
+    let df = ctx.table("user_table").await?;
+
+    // Filter users with score >= 90 and select a subset of columns
+    let df = df.filter(col("score").gt_eq(lit(90)))?.select(vec![
+        col("name"),
+        col("city"),
+        col("score"),
+    ])?;
+
+    // Expected output:
+    //
+    // +-------+-----------+-------+
+    // | name  | city      | score |
+    // +-------+-----------+-------+
+    // | Alice | New York  | 95    |
+    // | Paul  | Bengaluru | 91    |
+    // +-------+-----------+-------+
+
+    // Display the results
+    df.show().await?;
+
+    Ok(())
+}
+
+pub async fn create_catalog(warehouse: String) -> Result<Arc<dyn Catalog>, 
Box<dyn Error>> {
+    let mut options = Options::new();
+    options.set(CatalogOptions::WAREHOUSE, warehouse);
+    let catalog = CatalogFactory::create(options).await?;
+    Ok(catalog)
+}
diff --git a/crates/paimon/Cargo.toml b/crates/paimon/Cargo.toml
index d4049eb1..4c0bd8dd 100644
--- a/crates/paimon/Cargo.toml
+++ b/crates/paimon/Cargo.toml
@@ -54,7 +54,10 @@ storage-oss = [
 ]
 storage-s3 = ["dep:opendal-http-transport-reqwest", "dep:opendal-service-s3"]
 storage-cos = ["dep:opendal-http-transport-reqwest", "dep:opendal-service-cos"]
-storage-azdls = ["dep:opendal-http-transport-reqwest", 
"dep:opendal-service-azdls"]
+storage-azdls = [
+    "dep:opendal-http-transport-reqwest",
+    "dep:opendal-service-azdls",
+]
 storage-obs = ["dep:opendal-http-transport-reqwest", "dep:opendal-service-obs"]
 storage-gcs = ["dep:opendal-http-transport-reqwest", "dep:opendal-service-gcs"]
 storage-hdfs = ["dep:opendal-service-hdfs-native"]
@@ -64,7 +67,13 @@ url = "2.5.2"
 async-trait = "0.1.81"
 bytes = "1.7.1"
 bitflags = "2.6.0"
-tokio = { version = "1.39.2", features = ["fs", "io-util", "macros", "sync", 
"time"] }
+tokio = { version = "1.39.2", features = [
+    "fs",
+    "io-util",
+    "macros",
+    "sync",
+    "time",
+] }
 chrono = { version = "0.4.38", features = ["serde"] }
 serde = { version = "1", features = ["derive", "rc"] }
 serde_bytes = "0.11.15"
diff --git a/crates/paimon/examples/create_table.rs 
b/crates/paimon/examples/create_table.rs
new file mode 100644
index 00000000..5f9e8724
--- /dev/null
+++ b/crates/paimon/examples/create_table.rs
@@ -0,0 +1,134 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::collections::HashMap;
+use std::error::Error;
+use std::sync::Arc;
+
+use arrow_array::{Int32Array, RecordBatch, StringArray};
+use arrow_schema::{DataType as ArrowDataType, Field, Schema as ArrowSchema};
+use paimon::catalog::Identifier;
+use paimon::spec::{DataType, IntType, Schema, VarCharType};
+use paimon::{Catalog, CatalogFactory, CatalogOptions, Options};
+
+// This example creates a paimon table and inserts test data
+// Run the example by passing the catalog warehouse path first after `--`:
+// Eg: cargo run --package paimon --example create_table -- /path/to/warehouse 
--overwrite
+// Use optional --overwrite flag after the warehouse path to automatically 
drop and re-create
+// the table if it already exists.
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn Error>> {
+    let mut args = std::env::args().skip(1);
+
+    let warehouse = args.next().ok_or_else(|| {
+        std::io::Error::new(
+            std::io::ErrorKind::InvalidInput,
+            "usage: cargo run --package paimon --example create_table -- 
<warehouse-path> --overwrite",
+        )
+    })?;
+
+    let overwrite = args.any(|arg| arg == "--overwrite");
+
+    // Open local catalog
+    let catalog = create_catalog(warehouse).await?;
+
+    // Create new database
+    catalog
+        .create_database("my_db", true, HashMap::new())
+        .await?;
+
+    // Define table schema and its data types
+    let schema = Schema::builder()
+        .column("id", DataType::Int(IntType::new()))
+        .column("name", DataType::VarChar(VarCharType::string_type()))
+        .column("city", DataType::VarChar(VarCharType::string_type()))
+        .column("age", DataType::Int(IntType::new()))
+        .column("score", DataType::Int(IntType::new()))
+        .build()?;
+
+    let identifier = Identifier::new("my_db", "users");
+
+    // Check if table exists in catalog
+    let table_exists = match catalog.get_table(&identifier).await {
+        Ok(_) => true,
+        Err(paimon::Error::TableNotExist { .. }) => false,
+        Err(error) => return Err(error.into()),
+    };
+
+    if table_exists {
+        if !overwrite {
+            return Err(format!(
+                "table {} already exists, pass --overwrite to automatically 
drop and re-create it",
+                identifier
+            )
+            .into());
+        }
+
+        catalog.drop_table(&identifier, false).await?;
+    }
+    catalog.create_table(&identifier, schema, false).await?;
+
+    let table = catalog.get_table(&identifier).await?;
+
+    let builder = table.new_write_builder();
+    let txn = builder.new_commit();
+
+    let mut writer = builder.new_write()?;
+
+    let arrow_schema = Arc::new(ArrowSchema::new(vec![
+        Field::new("id", ArrowDataType::Int32, false),
+        Field::new("name", ArrowDataType::Utf8, false),
+        Field::new("city", ArrowDataType::Utf8, false),
+        Field::new("age", ArrowDataType::Int32, false),
+        Field::new("score", ArrowDataType::Int32, false),
+    ]));
+
+    // sample data
+    let batch = RecordBatch::try_new(
+        arrow_schema,
+        vec![
+            Arc::new(Int32Array::from(vec![1, 2, 3, 4, 5])),
+            Arc::new(StringArray::from(vec![
+                "Alice", "Bob", "Paul", "Diana", "Ethan",
+            ])),
+            Arc::new(StringArray::from(vec![
+                "New York",
+                "San Francisco",
+                "Bengaluru",
+                "Amsterdam",
+                "Berlin",
+            ])),
+            Arc::new(Int32Array::from(vec![28, 34, 22, 31, 27])),
+            Arc::new(Int32Array::from(vec![95, 82, 91, 88, 76])),
+        ],
+    )?;
+
+    writer.write_arrow_batch(&batch).await?;
+
+    let msg = writer.prepare_commit().await?;
+
+    txn.commit(msg).await?;
+
+    Ok(())
+}
+
+pub async fn create_catalog(warehouse: String) -> Result<Arc<dyn Catalog>, 
Box<dyn Error>> {
+    let mut options = Options::new();
+    options.set(CatalogOptions::WAREHOUSE, warehouse);
+    let catalog = CatalogFactory::create(options).await?;
+    Ok(catalog)
+}

Reply via email to