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

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 869eecd61 feat(core): object versioning APIs (#2614)
869eecd61 is described below

commit 869eecd6143180493bc8b0bba717ee96995deb69
Author: Suyan <[email protected]>
AuthorDate: Tue Jul 11 18:38:50 2023 +0800

    feat(core): object versioning APIs (#2614)
    
    * basic field in ops
    
    Signed-off-by: suyanhanx <[email protected]>
    
    * impl new method delete_with
    
    Signed-off-by: suyanhanx <[email protected]>
    
    ---------
    
    Signed-off-by: suyanhanx <[email protected]>
---
 core/src/lib.rs                             |  4 +--
 core/src/raw/ops.rs                         | 43 +++++++++++++++++++++++++++--
 core/src/types/metadata.rs                  | 40 +++++++++++++++++++++++++++
 core/src/types/operator/operator.rs         | 39 ++++++++++++++++++++++++--
 core/src/types/operator/operator_futures.rs | 33 ++++++++++++++++++++++
 5 files changed, 153 insertions(+), 6 deletions(-)

diff --git a/core/src/lib.rs b/core/src/lib.rs
index 71cfefb84..d4bf8d75b 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -89,8 +89,8 @@ mod tests {
     #[test]
     fn assert_size() {
         assert_eq!(24, size_of::<Operator>());
-        assert_eq!(240, size_of::<Entry>());
-        assert_eq!(216, size_of::<Metadata>());
+        assert_eq!(264, size_of::<Entry>());
+        assert_eq!(240, size_of::<Metadata>());
         assert_eq!(1, size_of::<EntryMode>());
         assert_eq!(24, size_of::<Scheme>());
     }
diff --git a/core/src/raw/ops.rs b/core/src/raw/ops.rs
index 2474f52cb..16194b0d7 100644
--- a/core/src/raw/ops.rs
+++ b/core/src/raw/ops.rs
@@ -40,12 +40,27 @@ impl OpCreateDir {
 ///
 /// The path must be normalized.
 #[derive(Debug, Clone, Default)]
-pub struct OpDelete {}
+pub struct OpDelete {
+    version: Option<String>,
+}
 
 impl OpDelete {
     /// Create a new `OpDelete`.
     pub fn new() -> Self {
-        Self {}
+        Self::default()
+    }
+}
+
+impl OpDelete {
+    /// Change the version of this delete operation.
+    pub fn with_version(mut self, version: &str) -> Self {
+        self.version = Some(version.into());
+        self
+    }
+
+    /// Get the version of this delete operation.
+    pub fn version(&self) -> Option<&str> {
+        self.version.as_deref()
     }
 }
 
@@ -229,6 +244,7 @@ pub struct OpRead {
     if_none_match: Option<String>,
     override_cache_control: Option<String>,
     override_content_disposition: Option<String>,
+    version: Option<String>,
 }
 
 impl OpRead {
@@ -292,6 +308,17 @@ impl OpRead {
     pub fn if_none_match(&self) -> Option<&str> {
         self.if_none_match.as_deref()
     }
+
+    /// Set the version of the option
+    pub fn with_version(mut self, version: &str) -> Self {
+        self.version = Some(version.to_string());
+        self
+    }
+
+    /// Get version from option
+    pub fn version(&self) -> Option<&str> {
+        self.version.as_deref()
+    }
 }
 
 /// Args for `stat` operation.
@@ -299,6 +326,7 @@ impl OpRead {
 pub struct OpStat {
     if_match: Option<String>,
     if_none_match: Option<String>,
+    version: Option<String>,
 }
 
 impl OpStat {
@@ -328,6 +356,17 @@ impl OpStat {
     pub fn if_none_match(&self) -> Option<&str> {
         self.if_none_match.as_deref()
     }
+
+    /// Set the version of the option
+    pub fn with_version(mut self, version: &str) -> Self {
+        self.version = Some(version.to_string());
+        self
+    }
+
+    /// Get version from option
+    pub fn version(&self) -> Option<&str> {
+        self.version.as_deref()
+    }
 }
 
 /// Args for `write` operation.
diff --git a/core/src/types/metadata.rs b/core/src/types/metadata.rs
index d341cdff6..02f5bb90d 100644
--- a/core/src/types/metadata.rs
+++ b/core/src/types/metadata.rs
@@ -44,6 +44,7 @@ pub struct Metadata {
     content_type: Option<String>,
     etag: Option<String>,
     last_modified: Option<DateTime<Utc>>,
+    version: Option<String>,
 }
 
 impl Metadata {
@@ -69,6 +70,7 @@ impl Metadata {
             last_modified: None,
             etag: None,
             content_disposition: None,
+            version: None,
         }
     }
 
@@ -418,6 +420,42 @@ impl Metadata {
         self.bit |= Metakey::ContentDisposition;
         self
     }
+
+    /// Version of this entry.
+    ///
+    /// Version is a string that can be used to identify the version of this 
entry.
+    ///
+    /// This field may come out from the version control system, like object 
versioning in AWS S3.
+    pub fn version(&self) -> Option<&str> {
+        debug_assert!(
+            self.bit.contains(Metakey::Version) || 
self.bit.contains(Metakey::Complete),
+            "visiting not set metadata: version, maybe a bug"
+        );
+
+        self.version.as_deref()
+    }
+
+    /// Set version of this entry.
+    ///
+    /// Version is a string that can be used to identify the version of this 
entry.
+    ///
+    /// This field may come out from the version control system, like object 
versioning in AWS S3.
+    pub fn with_version(mut self, v: String) -> Self {
+        self.version = Some(v);
+        self.bit |= Metakey::Version;
+        self
+    }
+
+    /// Set version of this entry.
+    ///
+    /// Version is a string that can be used to identify the version of this 
entry.
+    ///
+    /// This field may come out from the version control system, like object 
versioning in AWS S3.
+    pub fn set_version(&mut self, v: &str) -> &mut Self {
+        self.version = Some(v.to_string());
+        self.bit |= Metakey::Version;
+        self
+    }
 }
 
 flags! {
@@ -457,5 +495,7 @@ flags! {
         Etag,
         /// Key for last last modified.
         LastModified,
+        /// Key for version.
+        Version,
     }
 }
diff --git a/core/src/types/operator/operator.rs 
b/core/src/types/operator/operator.rs
index 157bf4efd..c36bf20c5 100644
--- a/core/src/types/operator/operator.rs
+++ b/core/src/types/operator/operator.rs
@@ -1073,11 +1073,46 @@ impl Operator {
     /// # }
     /// ```
     pub async fn delete(&self, path: &str) -> Result<()> {
+        self.delete_with(path).await
+    }
+
+    /// Delete the given path with extra options.
+    ///
+    /// # Notes
+    ///
+    /// - Deleting a file that does not exist won't return errors.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use anyhow::Result;
+    /// # use futures::io;
+    /// # use opendal::Operator;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// op.delete_with("test").await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn delete_with(&self, path: &str) -> FutureDelete {
         let path = normalize_path(path);
 
-        let _ = self.inner().delete(&path, OpDelete::new()).await?;
+        let fut = FutureDelete(OperatorFuture::new(
+            self.inner().clone(),
+            path,
+            OpDelete::default(),
+            |inner, path, args| {
+                let fut = async move {
+                    let _ = inner.delete(&path, args).await?;
+                    Ok(())
+                };
 
-        Ok(())
+                Box::pin(fut)
+            },
+        ));
+
+        fut
     }
 
     ///
diff --git a/core/src/types/operator/operator_futures.rs 
b/core/src/types/operator/operator_futures.rs
index 1998d97b3..6ab43d17a 100644
--- a/core/src/types/operator/operator_futures.rs
+++ b/core/src/types/operator/operator_futures.rs
@@ -131,6 +131,12 @@ impl FutureStat {
         self.0 = self.0.map_args(|args| args.with_if_none_match(v));
         self
     }
+
+    /// Set the version for this operation.
+    pub fn version(mut self, v: &str) -> Self {
+        self.0 = self.0.map_args(|args| args.with_version(v));
+        self
+    }
 }
 
 impl Future for FutureStat {
@@ -357,6 +363,12 @@ impl FutureRead {
         self.0 = self.0.map_args(|args| args.with_if_none_match(v));
         self
     }
+
+    /// Set the version for this operation.
+    pub fn version(mut self, v: &str) -> Self {
+        self.0 = self.0.map_args(|args| args.with_version(v));
+        self
+    }
 }
 
 impl Future for FutureRead {
@@ -508,6 +520,27 @@ impl Future for FutureWriter {
     }
 }
 
+/// Future that generated by [`Operator::delete_with`].
+///
+/// Users can add more options by public functions provided by this struct.
+pub struct FutureDelete(pub(crate) OperatorFuture<OpDelete, ()>);
+
+impl FutureDelete {
+    /// Change the version of this delete operation.
+    pub fn version(mut self, v: &str) -> Self {
+        self.0 = self.0.map_args(|args| args.with_version(v));
+        self
+    }
+}
+
+impl Future for FutureDelete {
+    type Output = Result<()>;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> 
Poll<Self::Output> {
+        self.0.poll_unpin(cx)
+    }
+}
+
 /// Future that generated by [`Operator::list_with`].
 ///
 /// Users can add more options by public functions provided by this struct.

Reply via email to