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

spmallette pushed a commit to branch TINKERPOP-3243
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 682ae7862a3457076523610a3688d6c6a7809369
Author: Stephen Mallette <[email protected]>
AuthorDate: Tue Jun 16 16:47:37 2026 -0400

    TINKERPOP-3243 Add next(n) batch iteration to gremlin-javascript
    
    Adds an overloaded next(amount) to Traversal that resolves to a
    Promise<Array> of up to `amount` result values, bringing gremlin-javascript
    to parity with next(n) in the Java, Python, .NET, and Go GLVs. Calling
    next() with no argument is unchanged and still returns the async-iterator
    item {value, done}. A short batch (fewer than requested) signals exhaustion
    and a non-positive amount yields an empty array, matching the other GLVs.
    
    Includes unit and integration test coverage and a CHANGELOG entry.
    
    Assisted-by: Claude Code:claude-opus-4-8
---
 CHANGELOG.asciidoc                                 |  1 +
 .../gremlin-javascript/lib/process/traversal.js    | 30 +++++++++--
 .../test/integration/traversal-test.js             | 20 +++++++
 .../gremlin-javascript/test/unit/traversal-test.js | 62 ++++++++++++++++++++++
 4 files changed, 108 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index e07f7b64a1..6908e7f63e 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 === TinkerPop 3.7.7 (Release Date: NOT OFFICIALLY RELEASED YET)
 
 * Added `NextN(n)` to `Traversal` in `gremlin-go` for batched result 
iteration, providing API parity with `next(n)` in the Java, Python, and .NET 
GLVs.
+* Added `next(n)` to `Traversal` in `gremlin-javascript` for batched result 
iteration, providing API parity with `next(n)` in the Java, Python, and .NET 
GLVs.
 * Fixed conjoin has incorrect null handling.
 * Expanded `gremlin-python` CI matrix to test against Python 3.9, 3.10, 3.11, 
3.12, and 3.13.
 * Add Node 26 support for `gremlin-javascript` and `gremlint`.
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
index a1ff9316dd..169ad63ba9 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/traversal.js
@@ -94,12 +94,32 @@ class Traversal {
   }
 
   /**
-   * Async iterator method implementation.
-   * Returns a promise containing an iterator item.
-   * @returns {Promise.<{value, done}>}
+   * Returns the next result from the traversal.
+   *
+   * When called without an argument, returns a Promise that resolves to an 
iterator
+   * item ({value, done}), following the async iterator protocol.
+   *
+   * When called with an amount, returns a Promise that resolves to an Array 
containing
+   * up to {@code amount} result values. If fewer results remain, the Array 
contains only
+   * those that remain. An amount of zero or less yields an empty Array.
+   * @param {Number} [amount] The number of results to retrieve.
+   * @returns {Promise.<{value, done}>|Promise.<Array>}
    */
-  next() {
-    return this._applyStrategies().then(() => this._getNext());
+  next(amount) {
+    if (amount === undefined || amount === null) {
+      return this._applyStrategies().then(() => this._getNext());
+    }
+    return this._applyStrategies().then(() => {
+      const result = [];
+      for (let i = 0; i < amount; i++) {
+        const it = this._getNext();
+        if (it.done) {
+          break;
+        }
+        result.push(it.value);
+      }
+      return result;
+    });
   }
 
   /**
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
index ede1ee8e52..31bb36425d 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/traversal-test.js
@@ -129,6 +129,26 @@ describe('Traversal', function () {
         });
     });
   });
+  describe('#next(amount)', function () {
+    it('should submit the traversal and return a batch of up to amount 
results', function () {
+      var g = traversal().withRemote(connection);
+      var t = g.V();
+      return t.next(2)
+        .then(function (batch) {
+          assert.ok(Array.isArray(batch));
+          assert.strictEqual(batch.length, 2);
+          batch.forEach(v => assert.ok(v instanceof Vertex));
+          return t.next(10);
+        }).then(function (batch) {
+          // gmodern has 6 vertices, 2 already consumed, so only 4 remain
+          assert.strictEqual(batch.length, 4);
+          batch.forEach(v => assert.ok(v instanceof Vertex));
+          return t.next(2);
+        }).then(function (batch) {
+          assert.deepStrictEqual(batch, []);
+        });
+    });
+  });
   describe('#materializeProperties()', function () {
     it('should skip vertex properties when tokens is set', function () {
       var g = traversal().withRemote(connection);
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js
index b794112f38..37a7920ca2 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/traversal-test.js
@@ -157,6 +157,68 @@ describe('Traversal', function () {
     });
   });
 
+  describe('#next(amount)', function () {
+    function createTraversal(traversers) {
+      const strategyMock = {
+        apply: function (traversal) {
+          traversal.traversers = traversers;
+          return Promise.resolve();
+        }
+      };
+      const strategies = new TraversalStrategies();
+      strategies.addStrategy(strategyMock);
+      return new t.Traversal(null, strategies, null);
+    }
+
+    it('should return a Promise with an array of up to amount values', 
function () {
+      const traversal = createTraversal([ new t.Traverser(1, 1), new 
t.Traverser(2, 1), new t.Traverser(3, 1) ]);
+      return traversal.next(2)
+        .then(function (batch) {
+          assert.deepStrictEqual(batch, [ 1, 2 ]);
+          return traversal.next(2);
+        })
+        .then(function (batch) {
+          assert.deepStrictEqual(batch, [ 3 ]);
+        });
+    });
+
+    it('should expand bulk into separate values', function () {
+      const traversal = createTraversal([ new t.Traverser(1, 2), new 
t.Traverser(2, 1) ]);
+      return traversal.next(2).then(function (batch) {
+        assert.deepStrictEqual(batch, [ 1, 1 ]);
+      });
+    });
+
+    it('should return only the remaining values when fewer than amount exist', 
function () {
+      const traversal = createTraversal([ new t.Traverser(1, 1), new 
t.Traverser(2, 1) ]);
+      return traversal.next(5).then(function (batch) {
+        assert.deepStrictEqual(batch, [ 1, 2 ]);
+      });
+    });
+
+    it('should return an empty array when amount is zero', function () {
+      const traversal = createTraversal([ new t.Traverser(1, 1) ]);
+      return traversal.next(0).then(function (batch) {
+        assert.deepStrictEqual(batch, []);
+      });
+    });
+
+    it('should return an empty array when amount is negative', function () {
+      const traversal = createTraversal([ new t.Traverser(1, 1) ]);
+      return traversal.next(-1).then(function (batch) {
+        assert.deepStrictEqual(batch, []);
+      });
+    });
+
+    it('should still return an iterator item when called without an amount', 
function () {
+      const traversal = createTraversal([ new t.Traverser(1, 1) ]);
+      return traversal.next().then(function (item) {
+        assert.strictEqual(item.value, 1);
+        assert.strictEqual(item.done, false);
+      });
+    });
+  });
+
   if (Symbol.asyncIterator) {
     describe('@@asyncIterator', function () {
       it('should expose the async iterator', function () {

Reply via email to