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 144214cbd feat(binding/nodejs): align list api (#3784)
144214cbd is described below

commit 144214cbd1cbabf1387fde7c8a2b266c94d7f4b6
Author: Suyan <[email protected]>
AuthorDate: Wed Dec 20 20:39:39 2023 +0800

    feat(binding/nodejs): align list api (#3784)
---
 bindings/nodejs/generated.d.ts | 102 +++++++++++---------------
 bindings/nodejs/src/lib.rs     | 161 +++++++++++++++++++----------------------
 bindings/nodejs/upgrade.md     |   7 ++
 3 files changed, 121 insertions(+), 149 deletions(-)

diff --git a/bindings/nodejs/generated.d.ts b/bindings/nodejs/generated.d.ts
index 9f45b248d..cb9e5e2fc 100644
--- a/bindings/nodejs/generated.d.ts
+++ b/bindings/nodejs/generated.d.ts
@@ -28,6 +28,10 @@ export class ExternalObject<T> {
     [K: symbol]: T
   }
 }
+export interface ListOptions {
+  limit?: number
+  recursive?: boolean
+}
 /** PresignedRequest is a presigned request return by `presign`. */
 export interface PresignedRequest {
   /** HTTP method of this request. */
@@ -349,53 +353,6 @@ export class Operator {
    * ```
    */
   renameSync(from: string, to: string): void
-  /**
-   * List dir in flat way.
-   *
-   * This function will create a new handle to list entries.
-   *
-   * An error will be returned if given path doesn't end with /.
-   *
-   * ### Example
-   *
-   * ```javascript
-   * const lister = await op.scan("/path/to/dir/");
-   * while (true) {
-   *   const entry = await lister.next();
-   *   if (entry === null) {
-   *     break;
-   *   }
-   *   let meta = await op.stat(entry.path);
-   *   if (meta.is_file) {
-   *     // do something
-   *   }
-   * }
-   * `````
-   */
-  scan(path: string): Promise<Lister>
-  /**
-   * List dir in flat way synchronously.
-   *
-   * This function will create a new handle to list entries.
-   *
-   * An error will be returned if given path doesn't end with /.
-   *
-   * ### Example
-   * ```javascript
-   * const lister = op.scan_sync(/path/to/dir/");
-   * while (true) {
-   *   const entry = lister.next();
-   *   if (entry === null) {
-   *     break;
-   *   }
-   *   let meta = op.statSync(entry.path);
-   *   if (meta.is_file) {
-   *     // do something
-   *   }
-   * }
-   * `````
-   */
-  scanSync(path: string): BlockingLister
   /**
    * Delete the given path.
    *
@@ -444,41 +401,64 @@ export class Operator {
   /**
    * List given path.
    *
-   * This function will create a new handle to list entries.
+   * This function will return an array of entries.
    *
    * An error will be returned if given path doesn't end with `/`.
    *
    * ### Example
+   *
    * ```javascript
-   * const lister = await op.list("path/to/dir/");
-   * while (true) {
-   *   const entry = await lister.next();
-   *   if (entry === null) {
-   *     break;
+   * const list = await op.list("path/to/dir/");
+   * for (let entry of list) {
+   *   let meta = await op.stat(entry.path);
+   *   if (meta.isFile) {
+   *     // do something
    *   }
+   * }
+   * ```
+   *
+   * #### List recursively
+   *
+   * With `recursive` option, you can list recursively.
+   *
+   * ```javascript
+   * const list = await op.list("path/to/dir/", { recursive: true });
+   * for (let entry of list) {
    *   let meta = await op.stat(entry.path);
    *   if (meta.isFile) {
    *     // do something
    *   }
    * }
    * ```
+   *
    */
-  list(path: string): Promise<Lister>
+  list(path: string, options?: ListOptions | undefined | null): 
Promise<Array<Entry>>
   /**
    * List given path synchronously.
    *
-   * This function will create a new handle to list entries.
+   * This function will return a array of entries.
    *
    * An error will be returned if given path doesn't end with `/`.
    *
    * ### Example
+   *
    * ```javascript
-   * const lister = op.listSync("path/to/dir/");
-   * while (true) {
-   *   const entry = lister.next();
-   *   if (entry === null) {
-   *     break;
+   * const list = op.listSync("path/to/dir/");
+   * for (let entry of list) {
+   *   let meta = op.statSync(entry.path);
+   *   if (meta.isFile) {
+   *     // do something
    *   }
+   * }
+   * ```
+   *
+   * #### List recursively
+   *
+   * With `recursive` option, you can list recursively.
+   *
+   * ```javascript
+   * const list = op.listSync("path/to/dir/", { recursive: true });
+   * for (let entry of list) {
    *   let meta = op.statSync(entry.path);
    *   if (meta.isFile) {
    *     // do something
@@ -486,7 +466,7 @@ export class Operator {
    * }
    * ```
    */
-  listSync(path: string): BlockingLister
+  listSync(path: string, options?: ListOptions | undefined | null): 
Array<Entry>
   /**
    * Get a presigned request for read.
    *
diff --git a/bindings/nodejs/src/lib.rs b/bindings/nodejs/src/lib.rs
index ee05ee2cf..f88a4d69f 100644
--- a/bindings/nodejs/src/lib.rs
+++ b/bindings/nodejs/src/lib.rs
@@ -341,70 +341,6 @@ impl Operator {
             .map_err(format_napi_error)
     }
 
-    /// List dir in flat way.
-    ///
-    /// This function will create a new handle to list entries.
-    ///
-    /// An error will be returned if given path doesn't end with /.
-    ///
-    /// ### Example
-    ///
-    /// ```javascript
-    /// const lister = await op.scan("/path/to/dir/");
-    /// while (true) {
-    ///   const entry = await lister.next();
-    ///   if (entry === null) {
-    ///     break;
-    ///   }
-    ///   let meta = await op.stat(entry.path);
-    ///   if (meta.is_file) {
-    ///     // do something
-    ///   }
-    /// }
-    /// `````
-    #[napi]
-    pub async fn scan(&self, path: String) -> Result<Lister> {
-        Ok(Lister(
-            self.0
-                .lister_with(&path)
-                .recursive(true)
-                .await
-                .map_err(format_napi_error)?,
-        ))
-    }
-
-    /// List dir in flat way synchronously.
-    ///
-    /// This function will create a new handle to list entries.
-    ///
-    /// An error will be returned if given path doesn't end with /.
-    ///
-    /// ### Example
-    /// ```javascript
-    /// const lister = op.scan_sync(/path/to/dir/");
-    /// while (true) {
-    ///   const entry = lister.next();
-    ///   if (entry === null) {
-    ///     break;
-    ///   }
-    ///   let meta = op.statSync(entry.path);
-    ///   if (meta.is_file) {
-    ///     // do something
-    ///   }
-    /// }
-    /// `````
-    #[napi]
-    pub fn scan_sync(&self, path: String) -> Result<BlockingLister> {
-        Ok(BlockingLister(
-            self.0
-                .blocking()
-                .lister_with(&path)
-                .recursive(true)
-                .call()
-                .map_err(format_napi_error)?,
-        ))
-    }
-
     /// Delete the given path.
     ///
     /// ### Notes
@@ -460,45 +396,80 @@ impl Operator {
 
     /// List given path.
     ///
-    /// This function will create a new handle to list entries.
+    /// This function will return an array of entries.
     ///
     /// An error will be returned if given path doesn't end with `/`.
     ///
     /// ### Example
+    ///
     /// ```javascript
-    /// const lister = await op.list("path/to/dir/");
-    /// while (true) {
-    ///   const entry = await lister.next();
-    ///   if (entry === null) {
-    ///     break;
+    /// const list = await op.list("path/to/dir/");
+    /// for (let entry of list) {
+    ///   let meta = await op.stat(entry.path);
+    ///   if (meta.isFile) {
+    ///     // do something
     ///   }
+    /// }
+    /// ```
+    ///
+    /// #### List recursively
+    ///
+    /// With `recursive` option, you can list recursively.
+    ///
+    /// ```javascript
+    /// const list = await op.list("path/to/dir/", { recursive: true });
+    /// for (let entry of list) {
     ///   let meta = await op.stat(entry.path);
     ///   if (meta.isFile) {
     ///     // do something
     ///   }
     /// }
     /// ```
+    ///
     #[napi]
-    pub async fn list(&self, path: String) -> Result<Lister> {
-        Ok(Lister(
-            self.0.lister(&path).await.map_err(format_napi_error)?,
-        ))
+    pub async fn list(&self, path: String, options: Option<ListOptions>) -> 
Result<Vec<Entry>> {
+        let mut l = self.0.list_with(&path);
+        if let Some(options) = options {
+            if let Some(limit) = options.limit {
+                l = l.limit(limit as usize);
+            }
+            if let Some(recursive) = options.recursive {
+                l = l.recursive(recursive);
+            }
+        }
+
+        Ok(l.await
+            .map_err(format_napi_error)?
+            .iter()
+            .map(|e| Entry(e.to_owned()))
+            .collect())
     }
 
     /// List given path synchronously.
     ///
-    /// This function will create a new handle to list entries.
+    /// This function will return a array of entries.
     ///
     /// An error will be returned if given path doesn't end with `/`.
     ///
     /// ### Example
+    ///
     /// ```javascript
-    /// const lister = op.listSync("path/to/dir/");
-    /// while (true) {
-    ///   const entry = lister.next();
-    ///   if (entry === null) {
-    ///     break;
+    /// const list = op.listSync("path/to/dir/");
+    /// for (let entry of list) {
+    ///   let meta = op.statSync(entry.path);
+    ///   if (meta.isFile) {
+    ///     // do something
     ///   }
+    /// }
+    /// ```
+    ///
+    /// #### List recursively
+    ///
+    /// With `recursive` option, you can list recursively.
+    ///
+    /// ```javascript
+    /// const list = op.listSync("path/to/dir/", { recursive: true });
+    /// for (let entry of list) {
     ///   let meta = op.statSync(entry.path);
     ///   if (meta.isFile) {
     ///     // do something
@@ -506,14 +477,22 @@ impl Operator {
     /// }
     /// ```
     #[napi]
-    pub fn list_sync(&self, path: String) -> Result<BlockingLister> {
-        Ok(BlockingLister(
-            self.0
-                .blocking()
-                .lister_with(&path)
-                .call()
-                .map_err(format_napi_error)?,
-        ))
+    pub fn list_sync(&self, path: String, options: Option<ListOptions>) -> 
Result<Vec<Entry>> {
+        let mut l = self.0.blocking().list_with(&path);
+        if let Some(options) = options {
+            if let Some(limit) = options.limit {
+                l = l.limit(limit as usize);
+            }
+            if let Some(recursive) = options.recursive {
+                l = l.recursive(recursive);
+            }
+        }
+
+        Ok(l.call()
+            .map_err(format_napi_error)?
+            .iter()
+            .map(|e| Entry(e.to_owned()))
+            .collect())
     }
 
     /// Get a presigned request for read.
@@ -656,6 +635,12 @@ impl Metadata {
     }
 }
 
+#[napi(object)]
+pub struct ListOptions {
+    pub limit: Option<u32>,
+    pub recursive: Option<bool>,
+}
+
 /// BlockingReader is designed to read data from given path in an blocking
 /// manner.
 #[napi]
diff --git a/bindings/nodejs/upgrade.md b/bindings/nodejs/upgrade.md
index 749610fdb..f697f599c 100644
--- a/bindings/nodejs/upgrade.md
+++ b/bindings/nodejs/upgrade.md
@@ -2,4 +2,11 @@
 
 ## Breaking change
 
+### Services
+
 Because of [a TLS lib 
issue](https://github.com/apache/incubator-opendal/issues/3650), we temporarily 
disable the `services-ftp` feature.
+
+### Public API
+
+Now, the `list` operation returns `Array<Entry>` instead of a lister.
+Also, we removed `scan`, you can use `list('some/path', {recursive: 
true})`/`listSync('some/path', {recursive: true})` instead of 
`scan('some/path')`/`scanSync('some/path')`.

Reply via email to