This is an automated email from the ASF dual-hosted git repository.
dentiny pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new dc0069760 feat(binding/go): add write with metadata (#7827)
dc0069760 is described below
commit dc0069760c7632bff80bc6a6142bfb633ca4dc9f
Author: Ryan Huang <[email protected]>
AuthorDate: Sat Jul 4 21:06:45 2026 +0900
feat(binding/go): add write with metadata (#7827)
---
bindings/c/include/opendal.h | 71 +++++++++++++
bindings/c/src/lib.rs | 1 +
bindings/c/src/operator.rs | 67 ++++++++++++
bindings/c/src/result.rs | 14 +++
bindings/c/src/writer.rs | 38 +++++++
bindings/go/examples/guide/getting_started.go | 2 +-
bindings/go/opendal.go | 4 +-
bindings/go/string_ownership_test.go | 36 +++++--
bindings/go/tests/behavior_tests/benchmark_test.go | 3 +-
bindings/go/tests/behavior_tests/copy_test.go | 70 +++++++-----
bindings/go/tests/behavior_tests/delete_test.go | 12 ++-
bindings/go/tests/behavior_tests/list_test.go | 45 +++++---
bindings/go/tests/behavior_tests/presign_test.go | 15 ++-
bindings/go/tests/behavior_tests/read_test.go | 60 +++++++----
bindings/go/tests/behavior_tests/rename_test.go | 28 +++--
bindings/go/tests/behavior_tests/stat_test.go | 31 ++++--
bindings/go/tests/behavior_tests/write_test.go | 99 +++++++++++++----
bindings/go/types.go | 14 +++
bindings/go/writer.go | 118 +++++++++++----------
19 files changed, 547 insertions(+), 181 deletions(-)
diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h
index c835d980c..692b164fb 100644
--- a/bindings/c/include/opendal.h
+++ b/bindings/c/include/opendal.h
@@ -384,6 +384,25 @@ typedef struct opendal_write_options {
uintptr_t user_metadata_len;
} opendal_write_options;
+/**
+ * \brief The result type returned by the metadata-returning write operations.
+ *
+ * Returned by opendal_operator_write_with_metadata() and
+ * opendal_writer_close_with_metadata(). On success the `meta` field holds the
+ * metadata of the just-written object (e.g. etag, version, last modified) and
+ * `error` is null; on failure `meta` is null and `error` is set.
+ */
+typedef struct opendal_result_write {
+ /**
+ * The metadata of the written object, or null on error.
+ */
+ struct opendal_metadata *meta;
+ /**
+ * The error, if ok, it is null
+ */
+ struct opendal_error *error;
+} opendal_result_write;
+
/**
* \brief The result type returned by opendal's read operation.
*
@@ -1511,6 +1530,43 @@ struct opendal_error *opendal_operator_write_with(const
struct opendal_operator
const struct opendal_bytes
*bytes,
const struct
opendal_write_options *opts);
+/**
+ * \brief Blocking write raw bytes to `path`, returning the written object's
metadata.
+ *
+ * Like `opendal_operator_write_with`, but on success returns the metadata of
the
+ * just-written object (e.g. etag, version, last modified) instead of
discarding it.
+ * A NULL `opts` is treated as the default options, behaving like a plain
write.
+ *
+ * @param op The opendal_operator created previously
+ * @param path The designated path where the data will be written
+ * @param bytes The data to write
+ * @param opts The write options, or NULL to use the defaults
+ * @see opendal_operator
+ * @see opendal_write_options
+ * @see opendal_result_write
+ * @return Returns opendal_result_write, containing the metadata and an
opendal_error.
+ * If the operation succeeds, the `meta` field holds the metadata and the
`error` field
+ * is null. Otherwise, the `meta` will be null and the `error` will be set
correspondingly.
+ *
+ * \note The returned metadata must be freed with opendal_metadata_free().
+ *
+ * # Safety
+ *
+ * It is **safe** under the cases below
+ * * The memory pointed to by `path` must contain a valid nul terminator at
the end of
+ * the string.
+ * * The `bytes` provided has valid byte in the `data` field and the `len`
field is set
+ * correctly.
+ *
+ * # Panic
+ *
+ * * If the `path` points to NULL, this function panics, i.e. exits with
information
+ */
+struct opendal_result_write opendal_operator_write_with_metadata(const struct
opendal_operator *op,
+ const char
*path,
+ const struct
opendal_bytes *bytes,
+ const struct
opendal_write_options *opts);
+
/**
* \brief Blocking read the data from `path`.
*
@@ -2879,6 +2935,21 @@ struct opendal_result_writer_write
opendal_writer_write(struct opendal_writer *s
*/
struct opendal_error *opendal_writer_close(struct opendal_writer *ptr);
+/**
+ * \brief Close the writer and return the written object's metadata.
+ *
+ * Like `opendal_writer_close`, but on success returns the metadata of the
+ * written object (e.g. etag, version, last modified) instead of discarding it.
+ *
+ * @param ptr The opendal_writer to close
+ * @see opendal_result_write
+ * @return Returns opendal_result_write. On success the `meta` field holds the
+ * metadata and `error` is null; on failure `meta` is null and `error` is set.
+ *
+ * \note The returned metadata must be freed with opendal_metadata_free().
+ */
+struct opendal_result_write opendal_writer_close_with_metadata(struct
opendal_writer *ptr);
+
/**
* \brief Frees the heap memory used by the opendal_writer.
*/
diff --git a/bindings/c/src/lib.rs b/bindings/c/src/lib.rs
index 9948055c5..ac44831fc 100644
--- a/bindings/c/src/lib.rs
+++ b/bindings/c/src/lib.rs
@@ -68,6 +68,7 @@ pub use result::opendal_result_operator_writer;
pub use result::opendal_result_read;
pub use result::opendal_result_reader_read;
pub use result::opendal_result_stat;
+pub use result::opendal_result_write;
pub use result::opendal_result_writer_write;
mod types;
diff --git a/bindings/c/src/operator.rs b/bindings/c/src/operator.rs
index ef2480818..9f7991c43 100644
--- a/bindings/c/src/operator.rs
+++ b/bindings/c/src/operator.rs
@@ -312,6 +312,73 @@ pub unsafe extern "C" fn opendal_operator_write_with(
}
}
+/// \brief Blocking write raw bytes to `path`, returning the written object's
metadata.
+///
+/// Like `opendal_operator_write_with`, but on success returns the metadata of
the
+/// just-written object (e.g. etag, version, last modified) instead of
discarding it.
+/// A NULL `opts` is treated as the default options, behaving like a plain
write.
+///
+/// @param op The opendal_operator created previously
+/// @param path The designated path where the data will be written
+/// @param bytes The data to write
+/// @param opts The write options, or NULL to use the defaults
+/// @see opendal_operator
+/// @see opendal_write_options
+/// @see opendal_result_write
+/// @return Returns opendal_result_write, containing the metadata and an
opendal_error.
+/// If the operation succeeds, the `meta` field holds the metadata and the
`error` field
+/// is null. Otherwise, the `meta` will be null and the `error` will be set
correspondingly.
+///
+/// \note The returned metadata must be freed with opendal_metadata_free().
+///
+/// # Safety
+///
+/// It is **safe** under the cases below
+/// * The memory pointed to by `path` must contain a valid nul terminator at
the end of
+/// the string.
+/// * The `bytes` provided has valid byte in the `data` field and the `len`
field is set
+/// correctly.
+///
+/// # Panic
+///
+/// * If the `path` points to NULL, this function panics, i.e. exits with
information
+#[no_mangle]
+pub unsafe extern "C" fn opendal_operator_write_with_metadata(
+ op: &opendal_operator,
+ path: *const c_char,
+ bytes: &opendal_bytes,
+ opts: *const opendal_write_options,
+) -> opendal_result_write {
+ assert!(!path.is_null());
+ let path = std::ffi::CStr::from_ptr(path)
+ .to_str()
+ .expect("malformed path");
+ let opts = if opts.is_null() {
+ core::options::WriteOptions::default()
+ } else {
+ (&*opts).into()
+ };
+ let bytes = match bytes.to_buffer() {
+ Ok(bytes) => bytes,
+ Err(e) => {
+ return opendal_result_write {
+ meta: std::ptr::null_mut(),
+ error: opendal_error::new(e),
+ }
+ }
+ };
+ match op.deref().write_options(path, bytes, opts) {
+ Ok(m) => opendal_result_write {
+ meta: Box::into_raw(Box::new(opendal_metadata::new(m))),
+ error: std::ptr::null_mut(),
+ },
+ Err(e) => opendal_result_write {
+ meta: std::ptr::null_mut(),
+ error: opendal_error::new(e),
+ },
+ }
+}
+
/// \brief Blocking read the data from `path`.
///
/// Read the data out from `path` blocking by operator.
diff --git a/bindings/c/src/result.rs b/bindings/c/src/result.rs
index 601a80138..0caaa40de 100644
--- a/bindings/c/src/result.rs
+++ b/bindings/c/src/result.rs
@@ -180,3 +180,17 @@ pub struct opendal_result_writer_write {
/// The error, if ok, it is null
pub error: *mut opendal_error,
}
+
+/// \brief The result type returned by the metadata-returning write operations.
+///
+/// Returned by opendal_operator_write_with_metadata() and
+/// opendal_writer_close_with_metadata(). On success the `meta` field holds the
+/// metadata of the just-written object (e.g. etag, version, last modified) and
+/// `error` is null; on failure `meta` is null and `error` is set.
+#[repr(C)]
+pub struct opendal_result_write {
+ /// The metadata of the written object, or null on error.
+ pub meta: *mut opendal_metadata,
+ /// The error, if ok, it is null
+ pub error: *mut opendal_error,
+}
diff --git a/bindings/c/src/writer.rs b/bindings/c/src/writer.rs
index acd5e39c8..3c61d8738 100644
--- a/bindings/c/src/writer.rs
+++ b/bindings/c/src/writer.rs
@@ -92,6 +92,44 @@ impl opendal_writer {
}
}
+ /// \brief Close the writer and return the written object's metadata.
+ ///
+ /// Like `opendal_writer_close`, but on success returns the metadata of the
+ /// written object (e.g. etag, version, last modified) instead of
discarding it.
+ ///
+ /// @param ptr The opendal_writer to close
+ /// @see opendal_result_write
+ /// @return Returns opendal_result_write. On success the `meta` field
holds the
+ /// metadata and `error` is null; on failure `meta` is null and `error` is
set.
+ ///
+ /// \note The returned metadata must be freed with opendal_metadata_free().
+ #[no_mangle]
+ pub unsafe extern "C" fn opendal_writer_close_with_metadata(
+ ptr: *mut opendal_writer,
+ ) -> opendal_result_write {
+ unsafe {
+ if ptr.is_null() {
+ return opendal_result_write {
+ meta: std::ptr::null_mut(),
+ error: std::ptr::null_mut(),
+ };
+ }
+ match (*ptr).deref_mut().close() {
+ Ok(m) => opendal_result_write {
+ meta: Box::into_raw(Box::new(opendal_metadata::new(m))),
+ error: std::ptr::null_mut(),
+ },
+ Err(e) => opendal_result_write {
+ meta: std::ptr::null_mut(),
+ error: opendal_error::new(
+ core::Error::new(core::ErrorKind::Unexpected, "close
writer failed")
+ .set_source(e),
+ ),
+ },
+ }
+ }
+ }
+
/// \brief Frees the heap memory used by the opendal_writer.
#[no_mangle]
pub unsafe extern "C" fn opendal_writer_free(ptr: *mut opendal_writer) {
diff --git a/bindings/go/examples/guide/getting_started.go
b/bindings/go/examples/guide/getting_started.go
index 49d20ebf8..21536d706 100644
--- a/bindings/go/examples/guide/getting_started.go
+++ b/bindings/go/examples/guide/getting_started.go
@@ -42,7 +42,7 @@ func main() {
defer op.Close() // Always close the operator to release resources.
// The same verbs work on every service.
- if err := op.Write("hello.txt", []byte("Hello, World!")); err != nil {
+ if _, err := op.Write("hello.txt", []byte("Hello, World!")); err != nil
{
log.Fatal(err)
}
diff --git a/bindings/go/opendal.go b/bindings/go/opendal.go
index d550faee7..bffcea0f2 100644
--- a/bindings/go/opendal.go
+++ b/bindings/go/opendal.go
@@ -46,7 +46,7 @@
// defer op.Close()
//
// // Perform operations using the operator
-// err = op.Write("example.txt", []byte("Hello, OpenDAL!"))
+// _, err = op.Write("example.txt", []byte("Hello, OpenDAL!"))
// if err != nil {
// log.Fatal(err)
// }
@@ -122,7 +122,7 @@ type OperatorOptions map[string]string
// defer op.Close() // Ensure the operator is closed when done
//
// // Perform operations using the operator
-// err = op.Write("example.txt", []byte("Hello, OpenDAL!"))
+// _, err = op.Write("example.txt", []byte("Hello, OpenDAL!"))
// if err != nil {
// log.Fatal(err)
// }
diff --git a/bindings/go/string_ownership_test.go
b/bindings/go/string_ownership_test.go
index 3b074c6f6..3c01bf536 100644
--- a/bindings/go/string_ownership_test.go
+++ b/bindings/go/string_ownership_test.go
@@ -674,30 +674,46 @@ func TestWriteWithOptions(t *testing.T) {
}
}
-func TestFfiOperatorWriteWithArgTypes(t *testing.T) {
- aTypes := ffiOperatorWriteWith.opts.aTypes
- if len(aTypes) != 4 {
- t.Fatalf("ffiOperatorWriteWith aTypes len = %d, want 4",
len(aTypes))
+func TestFfiOperatorWriterWithArgTypes(t *testing.T) {
+ aTypes := ffiOperatorWriterWith.opts.aTypes
+ if len(aTypes) != 3 {
+ t.Fatalf("ffiOperatorWriterWith aTypes len = %d, want 3",
len(aTypes))
}
for i, at := range aTypes {
if at != &ffi.TypePointer {
- t.Fatalf("ffiOperatorWriteWith aTypes[%d] = %v, want
TypePointer", i, at)
+ t.Fatalf("ffiOperatorWriterWith aTypes[%d] = %v, want
TypePointer", i, at)
}
}
}
-func TestFfiOperatorWriterWithArgTypes(t *testing.T) {
- aTypes := ffiOperatorWriterWith.opts.aTypes
- if len(aTypes) != 3 {
- t.Fatalf("ffiOperatorWriterWith aTypes len = %d, want 3",
len(aTypes))
+func TestFfiOperatorWriteWithMetadataSignature(t *testing.T) {
+ if ffiOperatorWriteWithMetadata.opts.rType != &typeResultWrite {
+ t.Fatalf("ffiOperatorWriteWithMetadata rType = %v, want
typeResultWrite", ffiOperatorWriteWithMetadata.opts.rType)
+ }
+ aTypes := ffiOperatorWriteWithMetadata.opts.aTypes
+ if len(aTypes) != 4 {
+ t.Fatalf("ffiOperatorWriteWithMetadata aTypes len = %d, want
4", len(aTypes))
}
for i, at := range aTypes {
if at != &ffi.TypePointer {
- t.Fatalf("ffiOperatorWriterWith aTypes[%d] = %v, want
TypePointer", i, at)
+ t.Fatalf("ffiOperatorWriteWithMetadata aTypes[%d] = %v,
want TypePointer", i, at)
}
}
}
+func TestFfiWriterCloseWithMetadataSignature(t *testing.T) {
+ if ffiWriterCloseWithMetadata.opts.rType != &typeResultWrite {
+ t.Fatalf("ffiWriterCloseWithMetadata rType = %v, want
typeResultWrite", ffiWriterCloseWithMetadata.opts.rType)
+ }
+ aTypes := ffiWriterCloseWithMetadata.opts.aTypes
+ if len(aTypes) != 1 {
+ t.Fatalf("ffiWriterCloseWithMetadata aTypes len = %d, want 1",
len(aTypes))
+ }
+ if aTypes[0] != &ffi.TypePointer {
+ t.Fatalf("ffiWriterCloseWithMetadata aTypes[0] = %v, want
TypePointer", aTypes[0])
+ }
+}
+
func TestWriteOptionsSetterArgTypes(t *testing.T) {
stringSetters := []*FFI[func(*opendalWriteOptions, string) ([]byte,
error)]{
ffiWriteOptionsSetCacheControl,
diff --git a/bindings/go/tests/behavior_tests/benchmark_test.go
b/bindings/go/tests/behavior_tests/benchmark_test.go
index 830e95103..a0aa164ea 100644
--- a/bindings/go/tests/behavior_tests/benchmark_test.go
+++ b/bindings/go/tests/behavior_tests/benchmark_test.go
@@ -137,7 +137,8 @@ func NewOpenDALReadWriter(op *opendal.Operator) ReadWriter {
}
func (rw *OpenDALReadWriter) Write(path string, data []byte) error {
- return rw.Operator.Write(path, data)
+ _, err := rw.Operator.Write(path, data)
+ return err
}
func (rw *OpenDALReadWriter) Read(path string) ([]byte, error) {
diff --git a/bindings/go/tests/behavior_tests/copy_test.go
b/bindings/go/tests/behavior_tests/copy_test.go
index 5f5ed1d1a..eb81559d5 100644
--- a/bindings/go/tests/behavior_tests/copy_test.go
+++ b/bindings/go/tests/behavior_tests/copy_test.go
@@ -60,7 +60,8 @@ func testsCopy(cap *opendal.Capability) []behaviorTest {
func testCopyFileWithASCIIName(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath := fixture.NewFilePath()
@@ -75,7 +76,8 @@ func testCopyFileWithNonASCIIName(assert *require.Assertions,
op *opendal.Operat
sourcePath, sourceContent, _ := fixture.NewFileWithPath("🐂🍺中文.docx")
targetPath := fixture.PushPath("😈🐅Français.docx")
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
assert.Nil(op.Copy(sourcePath, targetPath))
targetContent, err := op.Read(targetPath)
@@ -106,13 +108,14 @@ func testCopySourceDir(assert *require.Assertions, op
*opendal.Operator, fixture
func testCopyTargetDir(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath := fixture.NewDirPath()
assert.Nil(op.CreateDir(targetPath))
- err := op.Copy(sourcePath, targetPath)
+ err = op.Copy(sourcePath, targetPath)
assert.NotNil(err, "copy must fail")
assert.Equal(opendal.CodeIsADirectory, assertErrorCode(err))
}
@@ -120,9 +123,10 @@ func testCopyTargetDir(assert *require.Assertions, op
*opendal.Operator, fixture
func testCopySelf(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
- err := op.Copy(sourcePath, sourcePath)
+ err = op.Copy(sourcePath, sourcePath)
assert.NotNil(err, "copy must fail")
assert.Equal(opendal.CodeIsSameFile, assertErrorCode(err))
}
@@ -130,7 +134,8 @@ func testCopySelf(assert *require.Assertions, op
*opendal.Operator, fixture *fix
func testCopyNested(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath := fixture.PushPath(fmt.Sprintf(
"%s/%s/%s",
@@ -149,23 +154,26 @@ func testCopyNested(assert *require.Assertions, op
*opendal.Operator, fixture *f
func testCopyOverwrite(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath, targetContent, _ := fixture.NewFile()
assert.NotEqual(sourceContent, targetContent)
- assert.Nil(op.Write(targetPath, targetContent))
+ _, err = op.Write(targetPath, targetContent)
+ assert.Nil(err)
assert.Nil(op.Copy(sourcePath, targetPath))
- targetContent, err := op.Read(targetPath)
+ targetContent, err = op.Read(targetPath)
assert.Nil(err, "read must succeed")
assert.Equal(sourceContent, targetContent)
}
func testCopyWithIfNotExistsToNewFile(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath := fixture.NewFilePath()
assert.Nil(op.Copy(sourcePath, targetPath,
opendal.CopyWithIfNotExists(true)))
@@ -177,12 +185,14 @@ func testCopyWithIfNotExistsToNewFile(assert
*require.Assertions, op *opendal.Op
func testCopyWithIfNotExistsToExistingFile(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath, targetContent, _ := fixture.NewFile()
- assert.Nil(op.Write(targetPath, targetContent))
+ _, err = op.Write(targetPath, targetContent)
+ assert.Nil(err)
- err := op.Copy(sourcePath, targetPath,
opendal.CopyWithIfNotExists(true))
+ err = op.Copy(sourcePath, targetPath, opendal.CopyWithIfNotExists(true))
assert.NotNil(err)
assert.Equal(opendal.CodeConditionNotMatch, assertErrorCode(err))
@@ -193,11 +203,13 @@ func testCopyWithIfNotExistsToExistingFile(assert
*require.Assertions, op *opend
func testCopyWithIfMatchMatch(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath, targetContent, _ := fixture.NewFile()
assert.NotEqual(sourceContent, targetContent)
- assert.Nil(op.Write(targetPath, targetContent))
+ _, err = op.Write(targetPath, targetContent)
+ assert.Nil(err)
meta, err := op.Stat(targetPath)
assert.Nil(err, "stat must succeed")
@@ -212,13 +224,15 @@ func testCopyWithIfMatchMatch(assert *require.Assertions,
op *opendal.Operator,
func testCopyWithIfMatchMismatch(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath, targetContent, _ := fixture.NewFile()
assert.NotEqual(sourceContent, targetContent)
- assert.Nil(op.Write(targetPath, targetContent))
+ _, err = op.Write(targetPath, targetContent)
+ assert.Nil(err)
- err := op.Copy(sourcePath, targetPath,
opendal.CopyWithIfMatch("wrong-etag"))
+ err = op.Copy(sourcePath, targetPath,
opendal.CopyWithIfMatch("wrong-etag"))
assert.NotNil(err)
assert.Equal(opendal.CodeConditionNotMatch, assertErrorCode(err))
@@ -229,7 +243,8 @@ func testCopyWithIfMatchMismatch(assert
*require.Assertions, op *opendal.Operato
func testCopyWithSourceVersionToNewFile(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
meta, err := op.Stat(sourcePath)
assert.Nil(err, "stat must succeed")
@@ -239,7 +254,8 @@ func testCopyWithSourceVersionToNewFile(assert
*require.Assertions, op *opendal.
}
newContent := genFixedBytes(uint(len(sourceContent)) + 1)
- assert.Nil(op.Write(sourcePath, newContent), "overwrite must succeed")
+ _, err = op.Write(sourcePath, newContent)
+ assert.Nil(err, "overwrite must succeed")
targetPath := fixture.NewFilePath()
assert.Nil(op.Copy(sourcePath, targetPath,
opendal.CopyWithSourceVersion(version)))
@@ -251,7 +267,8 @@ func testCopyWithSourceVersionToNewFile(assert
*require.Assertions, op *opendal.
func testCopyWithSourceVersionToSameFile(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
meta, err := op.Stat(sourcePath)
assert.Nil(err, "stat must succeed")
@@ -261,7 +278,8 @@ func testCopyWithSourceVersionToSameFile(assert
*require.Assertions, op *opendal
}
newContent := genFixedBytes(uint(len(sourceContent)) + 1)
- assert.Nil(op.Write(sourcePath, newContent), "overwrite must succeed")
+ _, err = op.Write(sourcePath, newContent)
+ assert.Nil(err, "overwrite must succeed")
assert.Nil(op.Copy(sourcePath, sourcePath,
opendal.CopyWithSourceVersion(version)))
@@ -290,7 +308,8 @@ func testCopyWithChunk(assert *require.Assertions, op
*opendal.Operator, fixture
sourcePath := fixture.NewFilePath()
sourceContent := genFixedBytes(sourceSize)
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath := fixture.NewFilePath()
assert.Nil(op.Copy(sourcePath, targetPath,
opendal.CopyWithChunk(uint(chunk))))
@@ -308,7 +327,8 @@ func testCopyWithChunkAndConcurrent(assert
*require.Assertions, op *opendal.Oper
sourcePath := fixture.NewFilePath()
sourceContent := genFixedBytes(sourceSize)
- assert.Nil(op.Write(sourcePath, sourceContent))
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err)
targetPath := fixture.NewFilePath()
assert.Nil(op.Copy(sourcePath, targetPath,
opendal.CopyWithChunk(uint(chunk)), opendal.CopyWithConcurrent(4)))
diff --git a/bindings/go/tests/behavior_tests/delete_test.go
b/bindings/go/tests/behavior_tests/delete_test.go
index 32bd75b8f..702e59079 100644
--- a/bindings/go/tests/behavior_tests/delete_test.go
+++ b/bindings/go/tests/behavior_tests/delete_test.go
@@ -49,7 +49,8 @@ func testsDelete(cap *opendal.Capability) []behaviorTest {
func testDeleteFile(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
assert.Nil(op.Delete(path))
@@ -72,7 +73,8 @@ func testDeleteWithSpecialChars(assert *require.Assertions,
op *opendal.Operator
path := uuid.NewString() + " !@#$%^&()_+-=;',.txt"
path, content, _ := fixture.NewFileWithPath(path)
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
assert.Nil(op.Delete(path))
@@ -97,7 +99,8 @@ func testDeleteWithRecursive(assert *require.Assertions, op
*opendal.Operator, f
var filePaths []string
for i := range 3 {
path, content, _ :=
fixture.NewFileWithPath(fmt.Sprintf("%sfile-%d.txt", dir, i))
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
filePaths = append(filePaths, path)
}
@@ -112,7 +115,8 @@ func testDeleteWithRecursive(assert *require.Assertions, op
*opendal.Operator, f
func testDeleteWithVersion(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
diff --git a/bindings/go/tests/behavior_tests/list_test.go
b/bindings/go/tests/behavior_tests/list_test.go
index c681ba856..7a3f60488 100644
--- a/bindings/go/tests/behavior_tests/list_test.go
+++ b/bindings/go/tests/behavior_tests/list_test.go
@@ -71,7 +71,8 @@ func testListDir(assert *require.Assertions, op
*opendal.Operator, fixture *fixt
parent := fixture.NewDirPath()
path, content, size := fixture.NewFileWithPath(fmt.Sprintf("%s%s",
parent, uuid.NewString()))
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
obs, err := op.List(parent)
assert.Nil(err)
@@ -104,7 +105,8 @@ func testListRichDir(assert *require.Assertions, op
*opendal.Operator, fixture *
for range 10 {
path, content, _ := fixture.NewFileWithPath(fmt.Sprintf("%s%s",
parent, uuid.NewString()))
expected = append(expected, path)
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
}
obs, err := op.List(parent)
@@ -197,7 +199,8 @@ func testListNestedDir(assert *require.Assertions, op
*opendal.Operator, fixture
assert.Nil(op.CreateDir(parent), "create must succeed")
assert.Nil(op.CreateDir(dir), "create must succeed")
- assert.Nil(op.Write(filePath, []byte("test_list_nested_dir")), "write
must succeed")
+ _, err := op.Write(filePath, []byte("test_list_nested_dir"))
+ assert.Nil(err, "write must succeed")
assert.Nil(op.CreateDir(dirPath), "create must succeed")
obs, err := op.List(parent)
@@ -260,7 +263,8 @@ func testListEntryMetadata(assert *require.Assertions, op
*opendal.Operator, fix
assert.Nil(op.CreateDir(parent))
filePath, content, size := fixture.NewFileWithPath(fmt.Sprintf("%s%s",
parent, uuid.NewString()))
- assert.Nil(op.Write(filePath, content))
+ _, err := op.Write(filePath, content)
+ assert.Nil(err)
obs, err := op.List(parent)
assert.Nil(err)
@@ -294,7 +298,8 @@ func testListDirWithFilePath(assert *require.Assertions, op
*opendal.Operator, f
parent := fixture.NewDirPath()
path, content, _ := fixture.NewFileWithPath(fmt.Sprintf("%s%s", parent,
uuid.NewString()))
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
obs, err := op.List(strings.TrimSuffix(parent, "/"))
assert.Nil(err)
@@ -315,8 +320,10 @@ func testListWithDefaultOptions(assert
*require.Assertions, op *opendal.Operator
assert.Nil(op.CreateDir(parent))
assert.Nil(op.CreateDir(subDir))
- assert.Nil(op.Write(fileInParent, content))
- assert.Nil(op.Write(fileInSub, content))
+ _, err := op.Write(fileInParent, content)
+ assert.Nil(err)
+ _, err = op.Write(fileInSub, content)
+ assert.Nil(err)
obs, err := op.List(parent)
assert.Nil(err)
@@ -348,9 +355,12 @@ func testListWithRecursive(assert *require.Assertions, op
*opendal.Operator, fix
assert.Nil(op.CreateDir(parent))
assert.Nil(op.CreateDir(subDir))
assert.Nil(op.CreateDir(deepDir))
- assert.Nil(op.Write(fileTop, content))
- assert.Nil(op.Write(fileMid, content))
- assert.Nil(op.Write(fileDeep, content))
+ _, err := op.Write(fileTop, content)
+ assert.Nil(err)
+ _, err = op.Write(fileMid, content)
+ assert.Nil(err)
+ _, err = op.Write(fileDeep, content)
+ assert.Nil(err)
obs, err := op.List(parent, opendal.ListWithRecursive(true))
assert.Nil(err)
@@ -374,7 +384,8 @@ func testListWithLimit(assert *require.Assertions, op
*opendal.Operator, fixture
// Write 5 files.
for range 5 {
path, content, _ := fixture.NewFileWithPath(fmt.Sprintf("%s%s",
parent, uuid.NewString()))
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
}
// List with limit=2; the operation must succeed without error.
@@ -400,7 +411,8 @@ func testListWithStartAfter(assert *require.Assertions, op
*opendal.Operator, fi
for i := range 5 {
name := fmt.Sprintf("%sfile-%02d", parent, i)
filePaths = append(filePaths, name)
- assert.Nil(op.Write(name, []byte("content")))
+ _, err := op.Write(name, []byte("content"))
+ assert.Nil(err)
}
slices.Sort(filePaths)
@@ -426,8 +438,10 @@ func testListWithVersions(assert *require.Assertions, op
*opendal.Operator, fixt
parent := fixture.NewDirPath()
path, _, _ := fixture.NewFileWithPath(fmt.Sprintf("%s%s", parent,
uuid.NewString()))
- assert.Nil(op.Write(path, []byte("version-1")), "first write must
succeed")
- assert.Nil(op.Write(path, []byte("version-2")), "second write must
succeed")
+ _, err := op.Write(path, []byte("version-1"))
+ assert.Nil(err, "first write must succeed")
+ _, err = op.Write(path, []byte("version-2"))
+ assert.Nil(err, "second write must succeed")
obs, err := op.List(path, opendal.ListWithVersions(true))
assert.Nil(err, "list with versions must succeed")
@@ -457,7 +471,8 @@ func testListWithDeleted(assert *require.Assertions, op
*opendal.Operator, fixtu
parent := fixture.NewDirPath()
path, content, _ := fixture.NewFileWithPath(fmt.Sprintf("%s%s", parent,
uuid.NewString()))
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
obs, err := op.List(path, opendal.ListWithDeleted(true))
assert.Nil(err, "list with deleted must succeed before deletion")
diff --git a/bindings/go/tests/behavior_tests/presign_test.go
b/bindings/go/tests/behavior_tests/presign_test.go
index 39f80d6c9..eff7df225 100644
--- a/bindings/go/tests/behavior_tests/presign_test.go
+++ b/bindings/go/tests/behavior_tests/presign_test.go
@@ -80,7 +80,8 @@ func testPresignWrite(assert *require.Assertions, op
*opendal.Operator, fixture
func testPresignRead(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
req, err := op.PresignRead(path, time.Hour)
assert.Nil(err)
@@ -105,7 +106,8 @@ func testPresignReadWithRange(assert *require.Assertions,
op *opendal.Operator,
path := fixture.NewFilePath()
content := genFixedBytes(32)
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
req, err := op.PresignRead(path, time.Hour,
opendal.ReadWithRange(offset, length))
assert.Nil(err)
@@ -125,7 +127,8 @@ func testPresignReadWithRange(assert *require.Assertions,
op *opendal.Operator,
func testPresignStat(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
req, err := op.PresignStat(path, time.Hour)
assert.Nil(err)
@@ -146,7 +149,8 @@ func testPresignStatWithOverrideContentType(assert
*require.Assertions, op *open
path, content, _ := fixture.NewFile()
contentType := "application/octet-stream"
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
req, err := op.PresignStat(path, time.Hour,
opendal.StatWithOverrideContentType(contentType))
assert.Nil(err)
@@ -161,7 +165,8 @@ func testPresignStatWithOverrideContentType(assert
*require.Assertions, op *open
func testPresignDelete(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
req, err := op.PresignDelete(path, time.Hour)
assert.Nil(err)
diff --git a/bindings/go/tests/behavior_tests/read_test.go
b/bindings/go/tests/behavior_tests/read_test.go
index b7c49ade2..f5b7b8f1f 100644
--- a/bindings/go/tests/behavior_tests/read_test.go
+++ b/bindings/go/tests/behavior_tests/read_test.go
@@ -72,7 +72,8 @@ func testsRead(cap *opendal.Capability) []behaviorTest {
func testReadWithConcurrentChunkGap(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
bs, err := op.Read(path,
opendal.ReadWithConcurrent(2),
@@ -89,7 +90,8 @@ func testReadWithWriteOptions(assert *require.Assertions, op
*opendal.Operator,
content := genFixedBytes(1024 * 1024)
offset, length := genOffsetLength(uint(len(content)))
- assert.Nil(op.Write(path, content, opendal.WriteWithChunk(256*1024),
opendal.WriteWithConcurrent(2)))
+ _, err := op.Write(path, content, opendal.WriteWithChunk(256*1024),
opendal.WriteWithConcurrent(2))
+ assert.Nil(err)
bs, err := op.Read(path,
opendal.ReadWithRange(uint64(offset), uint64(length)),
@@ -105,7 +107,8 @@ func testReadWithWriteOptions(assert *require.Assertions,
op *opendal.Operator,
func testReadWithIfModifiedSince(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
@@ -123,7 +126,8 @@ func testReadWithIfModifiedSince(assert
*require.Assertions, op *opendal.Operato
func testReadWithIfUnmodifiedSince(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
@@ -141,7 +145,8 @@ func testReadWithIfUnmodifiedSince(assert
*require.Assertions, op *opendal.Opera
func testReadWithVersion(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
@@ -155,7 +160,8 @@ func testReadWithVersion(assert *require.Assertions, op
*opendal.Operator, fixtu
assert.Equal(content, data, "read content")
// After overwriting, the previous version data is still readable.
- assert.Nil(op.Write(path, []byte("1")), "overwrite must succeed")
+ _, err = op.Write(path, []byte("1"))
+ assert.Nil(err, "overwrite must succeed")
second, err := op.Read(path, opendal.ReadWithVersion(version))
assert.Nil(err)
assert.Equal(content, second, "read old version content")
@@ -165,7 +171,8 @@ func testReadWithRange(assert *require.Assertions, op
*opendal.Operator, fixture
path, content, size := fixture.NewFile()
offset, length := genOffsetLength(size)
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
bs, err := op.Read(path, opendal.ReadWithRange(uint64(offset),
uint64(length)))
assert.Nil(err)
@@ -177,7 +184,8 @@ func testReadWithRangeFrom(assert *require.Assertions, op
*opendal.Operator, fix
path, content, size := fixture.NewFile()
offset, _ := genOffsetLength(size)
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
bs, err := op.Read(path, opendal.ReadWithRangeFrom(uint64(offset)))
assert.Nil(err)
@@ -188,7 +196,8 @@ func testReadWithRangeFrom(assert *require.Assertions, op
*opendal.Operator, fix
func testReadWithContentLengthHint(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
// An accurate hint must not change the result of a full read.
bs, err := op.Read(path,
opendal.ReadWithContentLengthHint(uint64(size)))
@@ -210,7 +219,8 @@ func testReadWithContentLengthHint(assert
*require.Assertions, op *opendal.Opera
func testReadWithIfMatch(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
@@ -231,7 +241,8 @@ func testReadWithIfMatch(assert *require.Assertions, op
*opendal.Operator, fixtu
func testReadWithIfNoneMatch(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
@@ -252,7 +263,8 @@ func testReadWithIfNoneMatch(assert *require.Assertions, op
*opendal.Operator, f
func testReadFull(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
bs, err := op.Read(path)
assert.Nil(err)
@@ -263,7 +275,8 @@ func testReadFull(assert *require.Assertions, op
*opendal.Operator, fixture *fix
func testReader(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
r, err := op.Reader(path)
assert.Nil(err)
@@ -300,7 +313,8 @@ func testReadWithDirPath(assert *require.Assertions, op
*opendal.Operator, fixtu
func testReadWithSpecialChars(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, size := fixture.NewFileWithPath(uuid.NewString() + "
!@#$%^&()_+-=;',.txt")
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
bs, err := op.Read(path)
assert.Nil(err)
@@ -311,7 +325,8 @@ func testReadWithSpecialChars(assert *require.Assertions,
op *opendal.Operator,
func testIOCopy(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
r, err := op.Reader(path)
assert.Nil(err)
@@ -326,7 +341,8 @@ func testIOCopy(assert *require.Assertions, op
*opendal.Operator, fixture *fixtu
assert.Equal(size, uint(n), "read size")
assert.Nil(r.Close(), "close reader must succeed")
- assert.Nil(w.Close(), "close writer must succeed")
+ _, err = w.Close()
+ assert.Nil(err, "close writer must succeed")
copyContent, err := op.Read(pathCopy)
assert.Nil(err)
@@ -338,7 +354,8 @@ func testReaderSeek(assert *require.Assertions, op
*opendal.Operator, fixture *f
path, content, size := fixture.NewFile()
offset, length := genOffsetLength(size)
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
r, err := op.Reader(path)
assert.Nil(err)
@@ -375,7 +392,8 @@ func testReaderSeek(assert *require.Assertions, op
*opendal.Operator, fixture *f
func testReaderWithConcurrentChunkGap(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
r, err := op.Reader(path,
opendal.ReaderWithConcurrent(2),
@@ -396,7 +414,8 @@ func testReaderWithConcurrentChunkGap(assert
*require.Assertions, op *opendal.Op
func testReaderWithIfMatch(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
@@ -430,7 +449,8 @@ func testReaderWithIfMatch(assert *require.Assertions, op
*opendal.Operator, fix
func testReaderWithVersion(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
diff --git a/bindings/go/tests/behavior_tests/rename_test.go
b/bindings/go/tests/behavior_tests/rename_test.go
index 5a6f79b63..7775c25d6 100644
--- a/bindings/go/tests/behavior_tests/rename_test.go
+++ b/bindings/go/tests/behavior_tests/rename_test.go
@@ -45,13 +45,14 @@ func testsRename(cap *opendal.Capability) []behaviorTest {
func testRenameFile(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent), "write must succeed")
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err, "write must succeed")
targetPath := fixture.NewFilePath()
assert.Nil(op.Rename(sourcePath, targetPath))
- _, err := op.Stat(sourcePath)
+ _, err = op.Stat(sourcePath)
assert.NotNil(err, "stat must fail")
assert.Equal(opendal.CodeNotFound, assertErrorCode(err))
@@ -91,12 +92,13 @@ func testRenameTargetDir(assert *require.Assertions, op
*opendal.Operator, fixtu
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent), "write must succeed")
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err, "write must succeed")
targetPath := fixture.NewDirPath()
assert.Nil(op.CreateDir(targetPath))
- err := op.Rename(sourcePath, targetPath)
+ err = op.Rename(sourcePath, targetPath)
assert.NotNil(err)
assert.Equal(opendal.CodeIsADirectory, assertErrorCode(err))
}
@@ -104,9 +106,10 @@ func testRenameTargetDir(assert *require.Assertions, op
*opendal.Operator, fixtu
func testRenameSelf(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent), "write must succeed")
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err, "write must succeed")
- err := op.Rename(sourcePath, sourcePath)
+ err = op.Rename(sourcePath, sourcePath)
assert.NotNil(err)
assert.Equal(opendal.CodeIsSameFile, assertErrorCode(err))
}
@@ -114,7 +117,8 @@ func testRenameSelf(assert *require.Assertions, op
*opendal.Operator, fixture *f
func testRenameNested(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent), "write must succeed")
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err, "write must succeed")
targetPath := fixture.PushPath(fmt.Sprintf(
"%s/%s/%s",
@@ -125,7 +129,7 @@ func testRenameNested(assert *require.Assertions, op
*opendal.Operator, fixture
assert.Nil(op.Rename(sourcePath, targetPath))
- _, err := op.Stat(sourcePath)
+ _, err = op.Stat(sourcePath)
assert.NotNil(err, "stat must fail")
assert.Equal(opendal.CodeNotFound, assertErrorCode(err))
@@ -137,16 +141,18 @@ func testRenameNested(assert *require.Assertions, op
*opendal.Operator, fixture
func testRenameOverwrite(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
sourcePath, sourceContent, _ := fixture.NewFile()
- assert.Nil(op.Write(sourcePath, sourceContent), "write must succeed")
+ _, err := op.Write(sourcePath, sourceContent)
+ assert.Nil(err, "write must succeed")
targetPath, targetContent, _ := fixture.NewFile()
assert.NotEqual(sourceContent, targetContent)
- assert.Nil(op.Write(targetPath, targetContent), "write must succeed")
+ _, err = op.Write(targetPath, targetContent)
+ assert.Nil(err, "write must succeed")
assert.Nil(op.Rename(sourcePath, targetPath))
- _, err := op.Stat(sourcePath)
+ _, err = op.Stat(sourcePath)
assert.NotNil(err, "stat must fail")
assert.Equal(opendal.CodeNotFound, assertErrorCode(err))
diff --git a/bindings/go/tests/behavior_tests/stat_test.go
b/bindings/go/tests/behavior_tests/stat_test.go
index c47c84949..7bf9c3ad1 100644
--- a/bindings/go/tests/behavior_tests/stat_test.go
+++ b/bindings/go/tests/behavior_tests/stat_test.go
@@ -71,7 +71,8 @@ func assertOptionalMetaString(assert *require.Assertions,
name string, accessor
func testStatFile(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err)
@@ -113,7 +114,8 @@ func testStatNestedParentDir(assert *require.Assertions, op
*opendal.Operator, f
parent := fixture.NewDirPath()
path, content, _ := fixture.NewFileWithPath(fmt.Sprintf("%s%s", parent,
uuid.NewString()))
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(parent)
assert.Nil(err)
@@ -123,7 +125,8 @@ func testStatNestedParentDir(assert *require.Assertions, op
*opendal.Operator, f
func testStatWithSpecialChars(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, size := fixture.NewFileWithPath(uuid.NewString() + "
!@#$%^&()_+-=;',.txt")
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err)
@@ -134,7 +137,8 @@ func testStatWithSpecialChars(assert *require.Assertions,
op *opendal.Operator,
func testStatNotCleanedPath(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(fmt.Sprintf("//%s", path))
assert.Nil(err)
@@ -199,10 +203,13 @@ func testStatFileMetadata(assert *require.Assertions, op
*opendal.Operator, fixt
}
before := time.Now().Add(-time.Hour)
+ var err error
if len(writeOpts) == 0 {
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err = op.Write(path, content)
+ assert.Nil(err, "write must succeed")
} else {
- assert.Nil(op.Write(path, content, writeOpts...), "write with
metadata must succeed")
+ _, err = op.Write(path, content, writeOpts...)
+ assert.Nil(err, "write with metadata must succeed")
}
meta, err := op.Stat(path)
@@ -274,7 +281,8 @@ func testStatWithIfMatch(assert *require.Assertions, op
*opendal.Operator, fixtu
if isCapEnabled(cap.WriteWithContentType, "write_with_content_type") {
writeOpts = append(writeOpts,
opendal.WriteWithContentType("text/plain"))
}
- assert.Nil(op.Write(path, content, writeOpts...), "write must succeed")
+ _, err := op.Write(path, content, writeOpts...)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -300,7 +308,8 @@ func testStatWithIfNoneMatch(assert *require.Assertions, op
*opendal.Operator, f
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -326,7 +335,8 @@ func testStatWithIfModifiedSince(assert
*require.Assertions, op *opendal.Operato
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -353,7 +363,8 @@ func testStatWithIfUnmodifiedSince(assert
*require.Assertions, op *opendal.Opera
path, content, _ := fixture.NewFile()
- assert.Nil(op.Write(path, content), "write must succeed")
+ _, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
diff --git a/bindings/go/tests/behavior_tests/write_test.go
b/bindings/go/tests/behavior_tests/write_test.go
index 72084ad3b..976cbd35a 100644
--- a/bindings/go/tests/behavior_tests/write_test.go
+++ b/bindings/go/tests/behavior_tests/write_test.go
@@ -46,13 +46,16 @@ func testsWrite(cap *opendal.Capability) []behaviorTest {
testWriterWrite,
testWriteWithChunkAndConcurrent,
testWriterWithAppend,
+ testWriteReturnsMetadata,
+ testWriterCloseReturnsMetadata,
}
}
func testWriteOnly(assert *require.Assertions, op *opendal.Operator, fixture
*fixture) {
path, content, size := fixture.NewFile()
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -65,7 +68,8 @@ func testWriteWithEmptyContent(assert *require.Assertions, op
*opendal.Operator,
}
path := fixture.NewFilePath()
- assert.Nil(op.Write(path, []byte{}))
+ _, err := op.Write(path, []byte{})
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -75,7 +79,7 @@ func testWriteWithEmptyContent(assert *require.Assertions, op
*opendal.Operator,
func testWriteWithDirPath(assert *require.Assertions, op *opendal.Operator,
fixture *fixture) {
path := fixture.NewDirPath()
- err := op.Write(path, []byte("1"))
+ _, err := op.Write(path, []byte("1"))
assert.NotNil(err)
assert.Equal(opendal.CodeIsADirectory, assertErrorCode(err))
}
@@ -83,7 +87,8 @@ func testWriteWithDirPath(assert *require.Assertions, op
*opendal.Operator, fixt
func testWriteWithSpecialChars(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
path, content, size := fixture.NewFileWithPath(uuid.NewString() + "
!@#$%^&()_+-=;',.txt")
- assert.Nil(op.Write(path, content))
+ _, err := op.Write(path, content)
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -99,12 +104,14 @@ func testWriteOverwrite(assert *require.Assertions, op
*opendal.Operator, fixtur
size := uint(5 * 1024 * 1024)
contentOne, contentTwo := genFixedBytes(size), genFixedBytes(size)
- assert.Nil(op.Write(path, contentOne))
+ _, err := op.Write(path, contentOne)
+ assert.Nil(err)
bs, err := op.Read(path)
assert.Nil(err, "read must succeed")
assert.Equal(contentOne, bs, "read content_one")
- assert.Nil(op.Write(path, contentTwo))
+ _, err = op.Write(path, contentTwo)
+ assert.Nil(err)
bs, err = op.Read(path)
assert.Nil(err, "read must succeed")
assert.NotEqual(contentOne, bs, "content_one must be overwrote")
@@ -118,7 +125,8 @@ func testWriteWithCacheControl(assert *require.Assertions,
op *opendal.Operator,
path := fixture.NewFilePath()
content := []byte("hello")
- assert.Nil(op.Write(path, content,
opendal.WriteWithCacheControl("max-age=60")))
+ _, err := op.Write(path, content,
opendal.WriteWithCacheControl("max-age=60"))
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -135,7 +143,8 @@ func testWriteWithContentType(assert *require.Assertions,
op *opendal.Operator,
path := fixture.NewFilePath()
content := []byte("hello")
- assert.Nil(op.Write(path, content,
opendal.WriteWithContentType("text/plain")))
+ _, err := op.Write(path, content,
opendal.WriteWithContentType("text/plain"))
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -152,7 +161,8 @@ func testWriteWithContentDisposition(assert
*require.Assertions, op *opendal.Ope
path := fixture.NewFilePath()
content := []byte("hello")
- assert.Nil(op.Write(path, content,
opendal.WriteWithContentDisposition("attachment; filename=hello.txt")))
+ _, err := op.Write(path, content,
opendal.WriteWithContentDisposition("attachment; filename=hello.txt"))
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -169,7 +179,8 @@ func testWriteWithContentEncoding(assert
*require.Assertions, op *opendal.Operat
path := fixture.NewFilePath()
content := []byte("hello")
- assert.Nil(op.Write(path, content,
opendal.WriteWithContentEncoding("gzip")))
+ _, err := op.Write(path, content,
opendal.WriteWithContentEncoding("gzip"))
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -186,10 +197,11 @@ func testWriteWithUserMetadata(assert
*require.Assertions, op *opendal.Operator,
path := fixture.NewFilePath()
content := []byte("hello")
- assert.Nil(op.Write(path, content,
opendal.WriteWithUserMetadata(map[string]string{
+ _, err := op.Write(path, content,
opendal.WriteWithUserMetadata(map[string]string{
"language": "go",
"project": "opendal",
- })))
+ }))
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -206,13 +218,15 @@ func testWriteWithIfMatch(assert *require.Assertions, op
*opendal.Operator, fixt
}
path := fixture.NewFilePath()
- assert.Nil(op.Write(path, []byte("hello")))
+ _, err := op.Write(path, []byte("hello"))
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
etag, ok := meta.ETag()
assert.True(ok, "etag must exist")
- assert.Nil(op.Write(path, []byte("world"),
opendal.WriteWithIfMatch(etag)))
+ _, err = op.Write(path, []byte("world"), opendal.WriteWithIfMatch(etag))
+ assert.Nil(err)
bs, err := op.Read(path)
assert.Nil(err, "read must succeed")
assert.Equal([]byte("world"), bs)
@@ -224,13 +238,14 @@ func testWriteWithIfNoneMatch(assert *require.Assertions,
op *opendal.Operator,
}
path := fixture.NewFilePath()
- assert.Nil(op.Write(path, []byte("hello")))
+ _, err := op.Write(path, []byte("hello"))
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
etag, ok := meta.ETag()
assert.True(ok, "etag must exist")
- err = op.Write(path, []byte("world"),
opendal.WriteWithIfNoneMatch(etag))
+ _, err = op.Write(path, []byte("world"),
opendal.WriteWithIfNoneMatch(etag))
assert.NotNil(err)
assert.Equal(opendal.CodeConditionNotMatch, assertErrorCode(err))
@@ -245,8 +260,9 @@ func testWriteWithIfNotExists(assert *require.Assertions,
op *opendal.Operator,
}
path := fixture.NewFilePath()
- assert.Nil(op.Write(path, []byte("hello"),
opendal.WriteWithIfNotExists(true)))
- err := op.Write(path, []byte("world"),
opendal.WriteWithIfNotExists(true))
+ _, err := op.Write(path, []byte("hello"),
opendal.WriteWithIfNotExists(true))
+ assert.Nil(err)
+ _, err = op.Write(path, []byte("world"),
opendal.WriteWithIfNotExists(true))
assert.NotNil(err)
assert.Equal(opendal.CodeConditionNotMatch, assertErrorCode(err))
@@ -271,7 +287,8 @@ func testWriterWrite(assert *require.Assertions, op
*opendal.Operator, fixture *
assert.Nil(err)
_, err = w.Write(contentB)
assert.Nil(err)
- assert.Nil(w.Close())
+ _, err = w.Close()
+ assert.Nil(err)
meta, err := op.Stat(path)
assert.Nil(err, "stat must succeed")
@@ -291,7 +308,8 @@ func testWriteWithChunkAndConcurrent(assert
*require.Assertions, op *opendal.Ope
path := fixture.NewFilePath()
content := genFixedBytes(1024 * 1024)
- assert.Nil(op.Write(path, content, opendal.WriteWithChunk(256*1024),
opendal.WriteWithConcurrent(2)))
+ _, err := op.Write(path, content, opendal.WriteWithChunk(256*1024),
opendal.WriteWithConcurrent(2))
+ assert.Nil(err)
bs, err := op.Read(path)
assert.Nil(err, "read must succeed")
@@ -309,15 +327,52 @@ func testWriterWithAppend(assert *require.Assertions, op
*opendal.Operator, fixt
assert.Nil(err)
_, err = w.Write([]byte("hello"))
assert.Nil(err)
- assert.Nil(w.Close())
+ _, err = w.Close()
+ assert.Nil(err)
w, err = op.Writer(path, opendal.WriteWithAppend(true))
assert.Nil(err)
_, err = w.Write([]byte(" world"))
assert.Nil(err)
- assert.Nil(w.Close())
+ _, err = w.Close()
+ assert.Nil(err)
bs, err := op.Read(path)
assert.Nil(err, "read must succeed")
assert.Equal([]byte("hello world"), bs)
}
+
+func testWriteReturnsMetadata(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
+ path, content, _ := fixture.NewFile()
+
+ // Write returns the metadata of the written object. Which fields are
+ // populated is service-dependent (e.g. content length may be 0), so
only
+ // assert that metadata is returned and the content round-trips.
+ meta, err := op.Write(path, content)
+ assert.Nil(err, "write must succeed")
+ assert.NotNil(meta, "write must return metadata")
+
+ data, err := op.Read(path)
+ assert.Nil(err)
+ assert.Equal(content, data, "written content")
+}
+
+func testWriterCloseReturnsMetadata(assert *require.Assertions, op
*opendal.Operator, fixture *fixture) {
+ path := fixture.NewFilePath()
+ content := []byte("hello opendal write metadata")
+
+ w, err := op.Writer(path)
+ assert.Nil(err)
+ _, err = w.Write(content)
+ assert.Nil(err)
+
+ // Close returns the metadata of the written object; fields are
+ // service-dependent, so only assert that metadata is returned.
+ meta, err := w.Close()
+ assert.Nil(err, "close must succeed")
+ assert.NotNil(meta, "close must return metadata")
+
+ data, err := op.Read(path)
+ assert.Nil(err)
+ assert.Equal(content, data, "written content")
+}
diff --git a/bindings/go/types.go b/bindings/go/types.go
index c00e7dab8..8af6abaa2 100644
--- a/bindings/go/types.go
+++ b/bindings/go/types.go
@@ -63,6 +63,15 @@ var (
}[0],
}
+ typeResultWrite = ffi.Type{
+ Type: ffi.Struct,
+ Elements: &[]*ffi.Type{
+ &ffi.TypePointer,
+ &ffi.TypePointer,
+ nil,
+ }[0],
+ }
+
typeResultList = ffi.Type{
Type: ffi.Struct,
Elements: &[]*ffi.Type{
@@ -320,6 +329,11 @@ type resultStat struct {
error *opendalError
}
+type resultWrite struct {
+ meta *opendalMetadata
+ error *opendalError
+}
+
type resultPresign struct {
req *opendalPresignedRequest
error *opendalError
diff --git a/bindings/go/writer.go b/bindings/go/writer.go
index 9c4415fe0..ef77f2135 100644
--- a/bindings/go/writer.go
+++ b/bindings/go/writer.go
@@ -30,10 +30,13 @@ import (
"github.com/jupiterrider/ffi"
)
-// Write writes the given bytes to the specified path.
+// Write writes the given bytes to the specified path and returns the metadata
+// of the written object (such as etag, version, or last modified) as reported
+// by the underlying service.
//
-// Write is a wrapper around the C-binding function `opendal_operator_write`.
-// When options are provided, it uses `opendal_operator_write_with`.
+// Write is a wrapper around the C-binding function
+// `opendal_operator_write_with_metadata`. Which fields of the returned
Metadata
+// are populated depends on the service.
//
// # Parameters
//
@@ -43,32 +46,41 @@ import (
//
// # Returns
//
+// - *Metadata: Metadata of the written object. Which fields are populated
+// depends on the service.
// - error: An error if the write operation fails, or nil if successful.
//
// # Example
//
// func exampleWrite(op *opendal.Operator) {
-// err = op.Write("test", []byte("Hello opendal go binding!"))
+// _, err := op.Write("test", []byte("Hello opendal go binding!"))
// if err != nil {
// log.Fatal(err)
// }
// }
//
// Note: This example assumes proper error handling and import statements.
-func (op *Operator) Write(path string, data []byte, opts ...WithWriteFn) error
{
+func (op *Operator) Write(path string, data []byte, opts ...WithWriteFn)
(*Metadata, error) {
if len(opts) == 0 {
- return ffiOperatorWrite.symbol(op.ctx)(op.inner, path, data)
+ meta, err :=
ffiOperatorWriteWithMetadata.symbol(op.ctx)(op.inner, path, data, nil)
+ if err != nil {
+ return nil, err
+ }
+ return newMetadata(op.ctx, meta), nil
}
o := parseWriteOptions(opts...)
cOpts, keepAlive, err := newOpendalWriteOptions(op.ctx, o)
if err != nil {
- return err
+ return nil, err
}
defer ffiWriteOptionsFree.symbol(op.ctx)(cOpts)
- err = ffiOperatorWriteWith.symbol(op.ctx)(op.inner, path, data, cOpts)
+ meta, err := ffiOperatorWriteWithMetadata.symbol(op.ctx)(op.inner,
path, data, cOpts)
runtime.KeepAlive(keepAlive)
- return err
+ if err != nil {
+ return nil, err
+ }
+ return newMetadata(op.ctx, meta), nil
}
// WithWriteFn is a functional option for write operations.
@@ -373,7 +385,7 @@ type Writer struct {
// # Example
//
// func exampleWrite(op *opendal.Operator) {
-// err = op.Write("test", []byte("Hello opendal go binding!"))
+// _, err = op.Write("test", []byte("Hello opendal go binding!"))
// if err != nil {
// log.Fatal(err)
// }
@@ -384,58 +396,51 @@ func (w *Writer) Write(p []byte) (n int, err error) {
return ffiWriterWrite.symbol(w.ctx)(w.inner, p)
}
-// Close finishes the write and releases the resources associated with the
Writer.
-// It is important to call Close after writing all the data to ensure that the
data is
-// properly flushed and written to the storage. Otherwise, the data may be
lost.
-func (w *Writer) Close() error {
+// Close finishes the write and releases the resources associated with the
+// Writer, returning the metadata of the written object (such as etag, version,
+// or last modified) as reported by the underlying service.
+//
+// It is important to call Close after writing all the data to ensure that the
+// data is properly flushed and written to the storage. Otherwise, the data may
+// be lost.
+//
+// Close is a wrapper around the C-binding function
+// `opendal_writer_close_with_metadata`. Which fields of the returned Metadata
+// are populated depends on the service.
+func (w *Writer) Close() (*Metadata, error) {
defer ffiWriterFree.symbol(w.ctx)(w.inner)
- return ffiWriterClose.symbol(w.ctx)(w.inner)
+ meta, err := ffiWriterCloseWithMetadata.symbol(w.ctx)(w.inner)
+ if err != nil {
+ return nil, err
+ }
+ return newMetadata(w.ctx, meta), nil
}
-var _ io.WriteCloser = (*Writer)(nil)
+var _ io.Writer = (*Writer)(nil)
-var ffiOperatorWrite = newFFI(ffiOpts{
- sym: "opendal_operator_write",
- rType: &ffi.TypePointer,
- aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer,
&ffi.TypePointer},
-}, func(ctx context.Context, ffiCall ffiCall) func(op *opendalOperator, path
string, data []byte) error {
- return func(op *opendalOperator, path string, data []byte) error {
- bytePath, err := BytePtrFromString(path)
- if err != nil {
- return err
- }
- bytes := toOpendalBytes(data)
- var e *opendalError
- ffiCall(
- unsafe.Pointer(&e),
- unsafe.Pointer(&op),
- unsafe.Pointer(&bytePath),
- unsafe.Pointer(&bytes),
- )
- return parseError(ctx, e)
- }
-})
-
-var ffiOperatorWriteWith = newFFI(ffiOpts{
- sym: "opendal_operator_write_with",
- rType: &ffi.TypePointer,
+var ffiOperatorWriteWithMetadata = newFFI(ffiOpts{
+ sym: "opendal_operator_write_with_metadata",
+ rType: &typeResultWrite,
aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer,
&ffi.TypePointer, &ffi.TypePointer},
-}, func(ctx context.Context, ffiCall ffiCall) func(op *opendalOperator, path
string, data []byte, opts *opendalWriteOptions) error {
- return func(op *opendalOperator, path string, data []byte, opts
*opendalWriteOptions) error {
+}, func(ctx context.Context, ffiCall ffiCall) func(op *opendalOperator, path
string, data []byte, opts *opendalWriteOptions) (*opendalMetadata, error) {
+ return func(op *opendalOperator, path string, data []byte, opts
*opendalWriteOptions) (*opendalMetadata, error) {
bytePath, err := BytePtrFromString(path)
if err != nil {
- return err
+ return nil, err
}
bytes := toOpendalBytes(data)
- var e *opendalError
+ var result resultWrite
ffiCall(
- unsafe.Pointer(&e),
+ unsafe.Pointer(&result),
unsafe.Pointer(&op),
unsafe.Pointer(&bytePath),
unsafe.Pointer(&bytes),
unsafe.Pointer(&opts),
)
- return parseError(ctx, e)
+ if result.error != nil {
+ return nil, parseError(ctx, result.error)
+ }
+ return result.meta, nil
}
})
@@ -658,17 +663,20 @@ var ffiWriterWrite = newFFI(ffiOpts{
}
})
-var ffiWriterClose = newFFI(ffiOpts{
- sym: "opendal_writer_close",
- rType: &ffi.TypePointer,
+var ffiWriterCloseWithMetadata = newFFI(ffiOpts{
+ sym: "opendal_writer_close_with_metadata",
+ rType: &typeResultWrite,
aTypes: []*ffi.Type{&ffi.TypePointer},
-}, func(ctx context.Context, ffiCall ffiCall) func(r *opendalWriter) error {
- return func(r *opendalWriter) error {
- var e *opendalError
+}, func(ctx context.Context, ffiCall ffiCall) func(r *opendalWriter)
(*opendalMetadata, error) {
+ return func(r *opendalWriter) (*opendalMetadata, error) {
+ var result resultWrite
ffiCall(
- unsafe.Pointer(&e),
+ unsafe.Pointer(&result),
unsafe.Pointer(&r),
)
- return parseError(ctx, e)
+ if result.error != nil {
+ return nil, parseError(ctx, result.error)
+ }
+ return result.meta, nil
}
})