Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Simplify create API #225

Merged
merged 1 commit into from
Apr 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions docs/rfcs/0221-create-dir.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,10 @@ For example:
And we will support create an empty object:

```rust
// create a dir object "abc/", we will allow user ignore the ending "/"
let _ = op.object("abc").create_dir().await?;
// create a dir object "abc/"
let _ = op.object("abc/").create_dir().await?;
let _ = op.object("abc/").create().await?;
// create a file object "abc"
let _ = op.object("abc").create_file().await?;
// returns an error that `IsDir`.
let _ = op.object("abc/").create_file().await?;
let _ = op.object("abc").create().await?;
```

# Reference-level explanation
Expand All @@ -53,7 +49,7 @@ pub trait Accessor: Send + Sync + Debug {
}
```

`Object` will expose API like `create_dir` and `create_file` which will call `Accessor::create()` internally.
`Object` will expose API like `create` which will call `Accessor::create()` internally.

# Drawbacks

Expand Down Expand Up @@ -90,4 +86,4 @@ Until they get stabilized.

# Future possibilities

- `create_link` support.
None
37 changes: 16 additions & 21 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,15 @@ impl Object {
self.acc.clone()
}

/// Create an empty file object, like using `touch path/to/file` on linux.
/// Create an empty object, like using the following linux commands:
///
/// An error will be returned if object path ends with `/`.
/// - `touch path/to/file`
/// - `mkdir path/to/dir/`
///
/// # Examples
///
/// ## Create an empty file
///
/// ```
/// # use opendal::services::memory;
/// # use std::io::Result;
Expand All @@ -116,25 +119,12 @@ impl Object {
/// # async fn main() -> Result<()> {
/// # let op = Operator::new(memory::Backend::build().finish().await?);
/// let o = op.object("path/to/file");
/// let _ = o.create_file().await?;
/// let _ = o.create().await?;
/// # Ok(())
/// # }
/// ```
pub async fn create_file(&self) -> Result<()> {
let op = OpCreate::new(self.meta.path(), ObjectMode::FILE)?;
self.acc.create(&op).await
}

/// Create a dile object, like using `mkdir path/to/dir/` on linux.
///
/// An error will be returned if object path doesn't end with `/`.
///
/// # Notes
///
/// The trailing `/` in path `path/to/dir/` is required.
/// OpenDAL will treat all path endswith `/` as dir object.
///
/// # Examples
/// ## Create a dir
///
/// ```
/// # use opendal::services::memory;
Expand All @@ -145,13 +135,18 @@ impl Object {
/// # async fn main() -> Result<()> {
/// # let op = Operator::new(memory::Backend::build().finish().await?);
/// let o = op.object("path/to/dir/");
/// let _ = o.create_dir().await?;
/// let _ = o.create().await?;
/// # Ok(())
/// # }
/// ```
pub async fn create_dir(&self) -> Result<()> {
let op = OpCreate::new(self.meta.path(), ObjectMode::DIR)?;
self.acc.create(&op).await
pub async fn create(&self) -> Result<()> {
if self.meta.path.ends_with('/') {
let op = OpCreate::new(self.meta.path(), ObjectMode::DIR)?;
self.acc.create(&op).await
} else {
let op = OpCreate::new(self.meta.path(), ObjectMode::FILE)?;
self.acc.create(&op).await
}
}

/// Read the whole object into a bytes.
Expand Down
58 changes: 10 additions & 48 deletions tests/behavior/behavior.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ macro_rules! behavior_tests {
$service,

test_create_file,
test_create_file_with_dir_path,
test_create_dir,
test_create_dir_with_file_path,

test_write,
test_write_with_dir_path,
Expand Down Expand Up @@ -104,7 +102,7 @@ async fn test_create_file(op: Operator) -> Result<()> {

let o = op.object(&path);

let _ = o.create_file().await?;
let _ = o.create().await?;

let meta = o.metadata().await?;
assert_eq!(meta.path(), &path);
Expand All @@ -118,24 +116,13 @@ async fn test_create_file(op: Operator) -> Result<()> {
Ok(())
}

/// Create file with dir path should return an error.
async fn test_create_file_with_dir_path(op: Operator) -> Result<()> {
let path = format!("{}/", uuid::Uuid::new_v4());

let meta = op.object(&path).create_file().await;
assert!(meta.is_err());
assert!(meta.unwrap_err().to_string().contains("Is a directory"));

Ok(())
}

/// Create dir with dir path should succeed.
async fn test_create_dir(op: Operator) -> Result<()> {
let path = format!("{}/", uuid::Uuid::new_v4());

let o = op.object(&path);

let _ = o.create_dir().await?;
let _ = o.create().await?;

let meta = o.metadata().await?;
assert_eq!(meta.path(), &path);
Expand All @@ -148,21 +135,6 @@ async fn test_create_dir(op: Operator) -> Result<()> {
Ok(())
}

/// Create dir with file path should also succeed.
async fn test_create_dir_with_file_path(op: Operator) -> Result<()> {
let path = uuid::Uuid::new_v4().to_string();

let meta = op.object(&path).create_dir().await;
assert!(meta.is_err());
assert!(meta.unwrap_err().to_string().contains("Not a directory"));

op.object(&path)
.delete()
.await
.expect("delete must succeed");
Ok(())
}

/// Write a single file and test with stat.
async fn test_write(op: Operator) -> Result<()> {
let path = uuid::Uuid::new_v4().to_string();
Expand Down Expand Up @@ -225,11 +197,7 @@ async fn test_stat(op: Operator) -> Result<()> {
async fn test_stat_dir(op: Operator) -> Result<()> {
let path = format!("{}/", uuid::Uuid::new_v4());

let _ = op
.object(&path)
.create_dir()
.await
.expect("write must succeed");
let _ = op.object(&path).create().await.expect("write must succeed");

let meta = op.object(&path).metadata().await?;
assert_eq!(meta.mode(), ObjectMode::DIR);
Expand Down Expand Up @@ -359,11 +327,7 @@ async fn test_read_not_exist(op: Operator) -> Result<()> {
async fn test_read_with_dir_path(op: Operator) -> Result<()> {
let path = format!("{}/", uuid::Uuid::new_v4());

let _ = op
.object(&path)
.create_dir()
.await
.expect("write must succeed");
let _ = op.object(&path).create().await.expect("write must succeed");

let result = op.object(&path).read().await;
assert!(result.is_err());
Expand Down Expand Up @@ -412,11 +376,7 @@ async fn test_list_dir(op: Operator) -> Result<()> {
async fn test_list_sub_dir(op: Operator) -> Result<()> {
let path = format!("{}/", uuid::Uuid::new_v4());

let _ = op
.object(&path)
.create_dir()
.await
.expect("create_dir must succeed");
let _ = op.object(&path).create().await.expect("creat must succeed");

let mut obs = op.object("/").list().await?;
let mut found = false;
Expand Down Expand Up @@ -472,9 +432,11 @@ async fn test_delete(op: Operator) -> Result<()> {
async fn test_delete_empty_dir(op: Operator) -> Result<()> {
let path = format!("{}/", uuid::Uuid::new_v4());

let o = op.object(&path);

let _ = o.create_dir().await.expect("create_dir must succeed");
let _ = op
.object(&path)
.create()
.await
.expect("create must succeed");

let _ = op.object(&path).delete().await?;

Expand Down