Repository: jsonata-js/jsonata (js)

Issue:
Path expression on very large object causes RangeError
When mapping over objects that contain a large number of properties (>> 100000), the evaluator throws the js error `RangeError: Maximum call stack size exceeded`.

This is a bug in the flattening logic caused by the use of `Array.prototype.push.apply` to join arrays and is related to the known issue https://github.com/nodejs/node/issues/27732.

This bit of code needs rewriting.

Pull request description:
rewrite array flattening to avoid RangeError
resolves #434 

Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>

Patch:
diff --git a/src/functions.js b/src/functions.js
index e64d5ef..656c4ec 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -1671,7 +1671,7 @@ const functions = (() => {
                 var res =  lookup(input[ii], key);
                 if (typeof res !== 'undefined') {
                     if (Array.isArray(res)) {
-                        result.push(...res);
+                        res.forEach(val => result.push(val));
                     } else {
                         result.push(res);
                     }
diff --git a/src/jsonata.js b/src/jsonata.js
index 5924bac..aa40ccf 100644
--- a/src/jsonata.js
+++ b/src/jsonata.js
@@ -283,7 +283,7 @@ var jsonata = (function() {
                     resultSequence.push(res);
                 } else {
                     // res is a sequence - flatten it into the parent sequence
-                    Array.prototype.push.apply(resultSequence, res);
+                    res.forEach(val => resultSequence.push(val));
                 }
             });
         }


Test patch:
diff --git a/test/test-suite/groups/flattening/large.json b/test/test-suite/groups/flattening/large.json
new file mode 100644
index 0000000..a436972
--- /dev/null
+++ b/test/test-suite/groups/flattening/large.json
@@ -0,0 +1,16 @@
+[
+    {
+        "expr": "( $data := { 'number': [1..2e5].$string() }; $values := $data.number; $count($values) )",
+        "data": null,
+        "result": 200000,
+        "timelimit": 10000,
+        "depth": 10
+    },
+    {
+        "expr": "( $data := { 'number': [1..2e5].$string() }; $values := $lookup($data, 'number'); $count($values) )",
+        "data": null,
+        "result": 200000,
+        "timelimit": 10000,
+        "depth": 10
+    }
+]