diff --git a/arangod/RestHandler/RestCursorHandler.cpp b/arangod/RestHandler/RestCursorHandler.cpp index b95ff763ff..820cf30ba9 100644 --- a/arangod/RestHandler/RestCursorHandler.cpp +++ b/arangod/RestHandler/RestCursorHandler.cpp @@ -447,15 +447,19 @@ void RestCursorHandler::buildOptions(VPackSlice const& slice) { bool hasCache = false; bool hasMemoryLimit = false; VPackSlice opts = slice.get("options"); - bool isStream = false; + // "stream" option is important, so also accept it on top level and not only + // inside options + bool isStream = VelocyPackHelper::getBooleanValue(slice, "stream", false); if (opts.isObject()) { - isStream = VelocyPackHelper::getBooleanValue(opts, "stream", false); + if (!isStream) { + isStream = VelocyPackHelper::getBooleanValue(opts, "stream", false); + } for (auto const& it : VPackObjectIterator(opts)) { if (!it.key.isString() || it.value.isNone()) { continue; } - std::string keyName = it.key.copyString(); - if (keyName == "count" || keyName == "batchSize" || keyName == "ttl" || + velocypack::StringRef keyName = it.key.stringRef(); + if (keyName == "count" || keyName == "batchSize" || keyName == "ttl" || keyName == "stream" || (isStream && keyName == "fullCount")) { continue; // filter out top-level keys } else if (keyName == "cache") { @@ -466,6 +470,8 @@ void RestCursorHandler::buildOptions(VPackSlice const& slice) { _options->add(keyName, it.value); } } + + _options->add("stream", VPackValue(isStream)); if (!isStream) { // ignore cache & count for streaming queries bool val = VelocyPackHelper::getBooleanValue(slice, "count", false); diff --git a/js/client/modules/@arangodb/arango-statement.js b/js/client/modules/@arangodb/arango-statement.js index a128bf1983..8812def7f8 100644 --- a/js/client/modules/@arangodb/arango-statement.js +++ b/js/client/modules/@arangodb/arango-statement.js @@ -150,7 +150,8 @@ ArangoStatement.prototype.execute = function () { var body = { query: this._query, count: this._doCount, - bindVars: this._bindVars + bindVars: this._bindVars, + stream: this._stream }; if (this._batchSize) { @@ -170,8 +171,8 @@ ArangoStatement.prototype.execute = function () { arangosh.checkRequestResult(requestResult); - let isStream = false; - if (this._options && this._options.stream) { + let isStream = this._stream; + if (!isStream && this._options && this._options.stream) { isStream = this._options.stream; } diff --git a/js/common/modules/@arangodb/arango-statement-common.js b/js/common/modules/@arangodb/arango-statement-common.js index 66d2612648..58ab7ea2a1 100644 --- a/js/common/modules/@arangodb/arango-statement-common.js +++ b/js/common/modules/@arangodb/arango-statement-common.js @@ -38,6 +38,7 @@ function ArangoStatement (database, data) { this._bindVars = {}; this._options = undefined; this._cache = undefined; + this._stream = false; if (!data) { throw 'ArangoStatement needs initial data'; @@ -73,6 +74,9 @@ function ArangoStatement (database, data) { if (data.cache !== undefined) { this.setCache(data.cache); } + if (data.stream !== undefined) { + this._stream = data.stream; + } } // ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/js/client/shell/shell-statement.js b/tests/js/client/shell/shell-statement.js index 63cf85a91f..349a782edc 100644 --- a/tests/js/client/shell/shell-statement.js +++ b/tests/js/client/shell/shell-statement.js @@ -197,6 +197,21 @@ function StatementStreamSuite () { assertFalse(cursor.hasNext()); }, + + testStreamCursorOnTopLevel : function () { + var stmt = db._createStatement({ query: "FOR i IN 1..100 RETURN i", + stream: true, + batchSize: 50}); + var cursor = stmt.execute(); + + assertEqual(undefined, cursor.count()); + for (var i = 1; i <= 100; ++i) { + assertEqual(i, cursor.next()); + assertEqual(i !== 100, cursor.hasNext()); + } + + assertFalse(cursor.hasNext()); + }, //////////////////////////////////////////////////////////////////////////////// /// @brief test to string @@ -220,6 +235,27 @@ function StatementStreamSuite () { assertEqual(i !== 11, cursor.hasNext()); } + assertFalse(cursor.hasNext()); + }, + + testStreamToStringOnTopLevel : function () { + var stmt = db._createStatement({ query: "FOR i IN 1..11 RETURN i", + stream: true }); + var cursor = stmt.execute(); + + assertEqual(undefined, cursor.count()); // count is not supported + assertTrue(cursor.hasNext()); + + // print it. this should not modify the cursor apart from when it's accessed for printing + cursor.toString(); + assertTrue(more === cursor); + assertTrue(cursor._stream); + + for (var i = 1; i <= 11; ++i) { + assertEqual(i, cursor.next()); + assertEqual(i !== 11, cursor.hasNext()); + } + assertFalse(cursor.hasNext()); }