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

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


The following commit(s) were added to refs/heads/main by this push:
     new 6e29ca7  feat (static table): implement a read-only table struct 
loaded from metadata (#259)
6e29ca7 is described below

commit 6e29ca77fb48ea1c862efc325de93c15ea064c01
Author: Alon Agmon <[email protected]>
AuthorDate: Fri Mar 15 11:10:21 2024 +0200

    feat (static table): implement a read-only table struct loaded from 
metadata (#259)
    
    * fixing some broken branch
    
    * adding readonly property to Table, and setting readonly value on 
StaticTable
---
 crates/iceberg/src/table.rs | 165 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)

diff --git a/crates/iceberg/src/table.rs b/crates/iceberg/src/table.rs
index e3260a8..839969d 100644
--- a/crates/iceberg/src/table.rs
+++ b/crates/iceberg/src/table.rs
@@ -19,7 +19,9 @@
 use crate::io::FileIO;
 use crate::scan::TableScanBuilder;
 use crate::spec::{TableMetadata, TableMetadataRef};
+use crate::Result;
 use crate::TableIdent;
+use futures::AsyncReadExt;
 use typed_builder::TypedBuilder;
 
 /// Table represents a table in the catalog.
@@ -31,6 +33,8 @@ pub struct Table {
     #[builder(setter(into))]
     metadata: TableMetadataRef,
     identifier: TableIdent,
+    #[builder(default = false)]
+    readonly: bool,
 }
 
 impl Table {
@@ -62,4 +66,165 @@ impl Table {
     pub fn scan(&self) -> TableScanBuilder<'_> {
         TableScanBuilder::new(self)
     }
+
+    /// Returns the flag indicating whether the `Table` is readonly or not
+    pub fn readonly(&self) -> bool {
+        self.readonly
+    }
+}
+
+/// `StaticTable` is a read-only table struct that can be created from a 
metadata file or from `TableMetaData` without a catalog.
+/// It can only be used to read metadata and for table scan.
+/// # Examples
+///
+/// ```rust, no_run
+/// # use iceberg::io::FileIO;
+/// # use iceberg::table::StaticTable;
+/// # use iceberg::TableIdent;
+/// # async fn example() {
+/// let metadata_file_location = "s3://bucket_name/path/to/metadata.json";
+/// let file_io = 
FileIO::from_path(&metadata_file_location).unwrap().build().unwrap();
+/// let static_identifier = TableIdent::from_strs(["static_ns", 
"static_table"]).unwrap();
+/// let static_table = 
StaticTable::from_metadata_file(&metadata_file_location, static_identifier, 
file_io).await.unwrap();
+/// let snapshot_id = static_table
+/// .metadata()
+/// .current_snapshot()
+/// .unwrap()
+/// .snapshot_id();
+/// # }
+/// ```
+pub struct StaticTable(Table);
+
+impl StaticTable {
+    /// Creates a static table from a given `TableMetadata` and `FileIO`
+    pub async fn from_metadata(
+        metadata: TableMetadata,
+        table_ident: TableIdent,
+        file_io: FileIO,
+    ) -> Result<Self> {
+        let table = Table::builder()
+            .metadata(metadata)
+            .identifier(table_ident)
+            .file_io(file_io)
+            .readonly(true)
+            .build();
+
+        Ok(Self(table))
+    }
+    /// Creates a static table directly from metadata file and `FileIO`
+    pub async fn from_metadata_file(
+        metadata_file_path: &str,
+        table_ident: TableIdent,
+        file_io: FileIO,
+    ) -> Result<Self> {
+        let metadata_file = file_io.new_input(metadata_file_path)?;
+        let mut metadata_file_reader = metadata_file.reader().await?;
+        let mut metadata_file_content = String::new();
+        metadata_file_reader
+            .read_to_string(&mut metadata_file_content)
+            .await?;
+        let table_metadata = 
serde_json::from_str::<TableMetadata>(&metadata_file_content)?;
+        Self::from_metadata(table_metadata, table_ident, file_io).await
+    }
+
+    /// Create a TableScanBuilder for the static table.
+    pub fn scan(&self) -> TableScanBuilder<'_> {
+        self.0.scan()
+    }
+
+    /// Get TableMetadataRef for the static table
+    pub fn metadata(&self) -> TableMetadataRef {
+        self.0.metadata_ref()
+    }
+
+    /// Consumes the `StaticTable` and return it as a `Table`    
+    /// Please use this method carefully as the Table it returns remains 
detached from a catalog     
+    /// and can't be used to perform modifications on the table.     
+    pub fn into_table(self) -> Table {
+        self.0
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[tokio::test]
+    async fn test_static_table_from_file() {
+        let metadata_file_name = "TableMetadataV2Valid.json";
+        let metadata_file_path = format!(
+            "{}/testdata/table_metadata/{}",
+            env!("CARGO_MANIFEST_DIR"),
+            metadata_file_name
+        );
+        let file_io = FileIO::from_path(&metadata_file_path)
+            .unwrap()
+            .build()
+            .unwrap();
+        let static_identifier = TableIdent::from_strs(["static_ns", 
"static_table"]).unwrap();
+        let static_table =
+            StaticTable::from_metadata_file(&metadata_file_path, 
static_identifier, file_io)
+                .await
+                .unwrap();
+        let snapshot_id = static_table
+            .metadata()
+            .current_snapshot()
+            .unwrap()
+            .snapshot_id();
+        assert_eq!(
+            snapshot_id, 3055729675574597004,
+            "snapshot id from metadata don't match"
+        );
+    }
+
+    #[tokio::test]
+    async fn test_static_into_table() {
+        let metadata_file_name = "TableMetadataV2Valid.json";
+        let metadata_file_path = format!(
+            "{}/testdata/table_metadata/{}",
+            env!("CARGO_MANIFEST_DIR"),
+            metadata_file_name
+        );
+        let file_io = FileIO::from_path(&metadata_file_path)
+            .unwrap()
+            .build()
+            .unwrap();
+        let static_identifier = TableIdent::from_strs(["static_ns", 
"static_table"]).unwrap();
+        let static_table =
+            StaticTable::from_metadata_file(&metadata_file_path, 
static_identifier, file_io)
+                .await
+                .unwrap();
+        let table = static_table.into_table();
+        assert!(table.readonly());
+        assert_eq!(table.identifier.name(), "static_table");
+    }
+
+    #[tokio::test]
+    async fn test_table_readonly_flag() {
+        let metadata_file_name = "TableMetadataV2Valid.json";
+        let metadata_file_path = format!(
+            "{}/testdata/table_metadata/{}",
+            env!("CARGO_MANIFEST_DIR"),
+            metadata_file_name
+        );
+        let file_io = FileIO::from_path(&metadata_file_path)
+            .unwrap()
+            .build()
+            .unwrap();
+        let metadata_file = file_io.new_input(metadata_file_path).unwrap();
+        let mut metadata_file_reader = metadata_file.reader().await.unwrap();
+        let mut metadata_file_content = String::new();
+        metadata_file_reader
+            .read_to_string(&mut metadata_file_content)
+            .await
+            .unwrap();
+        let table_metadata = 
serde_json::from_str::<TableMetadata>(&metadata_file_content).unwrap();
+        let static_identifier = TableIdent::from_strs(["ns", 
"table"]).unwrap();
+        let table = Table::builder()
+            .metadata(table_metadata)
+            .identifier(static_identifier)
+            .file_io(file_io)
+            .build();
+        assert!(!table.readonly());
+        assert_eq!(table.identifier.name(), "table");
+    }
 }

Reply via email to