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.