Repository: jsonata-js/jsonata (js)

Issue:
Incorrect results for positional variable operator '#' on input arrays
The `#` operator introduced in v1.7.0 is not working as designed for input JSON with top-level arrays.  For example, the expression `$#$pos[$pos < 3]` is saying 'bind the variable $pos to the position (index) of each value in the input array, then filter the results to contain only those with index less than 3'.  When applied to the input array `[3,1,4,1,5,9]`, it should return `[3,1,4]`.   However, in v1.7.0, it is returning nothing.  This expression is equivalent to the expression `$[[0..2]]`, which returns the correct `[3,1,4]`.


Pull request description:
fix generation of tuple stream from input arrays
Fix code and test cases (+ add more) for tuple generating syntax (joins) on top level arrays

resolves #382 

Signed-off-by: andrew-coleman <andrew_coleman@uk.ibm.com>

Patch:
diff --git a/src/jsonata.js b/src/jsonata.js
index df12d7a..b43355b 100644
--- a/src/jsonata.js
+++ b/src/jsonata.js
@@ -163,9 +163,7 @@ var jsonata = (function() {
         // expr is an array of steps
         // if the first step is a variable reference ($...), including root reference ($$),
         //   then the path is absolute rather than relative
-        if (expr.steps[0].type === 'variable') {
-            inputSequence = createSequence(input);  // dummy singleton sequence for first (absolute) step
-        } else if (Array.isArray(input)) {
+        if (Array.isArray(input) && expr.steps[0].type !== 'variable') {
             inputSequence = input;
         } else {
             // if input is not an array, make it so
@@ -334,7 +332,7 @@ var jsonata = (function() {
         result.tupleStream = true;
         var stepEnv = environment;
         if(tupleBindings === undefined) {
-            tupleBindings = [{'@': input}];
+            tupleBindings = input.map(item => { return {'@': item} });
         }
 
         for(var ee = 0; ee < tupleBindings.length; ee++) {
diff --git a/src/parser.js b/src/parser.js
index cbe02d4..7437aaf 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -1012,7 +1012,7 @@ const parser = (() => {
                             }
                             // throw error if there are any predicates defined at this point
                             // at this point the only type of stages can be predicates
-                            if(typeof step.stages !== 'undefined') {
+                            if(typeof step.stages !== 'undefined' || typeof step.predicate !== 'undefined') {
                                 throw {
                                     code: "S0215",
                                     stack: (new Error()).stack,
@@ -1038,6 +1038,12 @@ const parser = (() => {
                             step = result;
                             if (result.type === 'path') {
                                 step = result.steps[result.steps.length - 1];
+                            } else {
+                                result = {type: 'path', steps: [result]};
+                                if (typeof step.predicate !== 'undefined') {
+                                    step.stages = step.predicate;
+                                    delete step.predicate;
+                                }
                             }
                             if (typeof step.stages === 'undefined') {
                                 step.index = expr.rhs.value;


Test patch:
diff --git a/test/test-suite/groups/joins/index.json b/test/test-suite/groups/joins/index.json
index 3ee7b8e..1fc48f1 100644
--- a/test/test-suite/groups/joins/index.json
+++ b/test/test-suite/groups/joins/index.json
@@ -1,6 +1,6 @@
 [
     {
-        "expr": "$.$#$pos[$pos<3]",
+        "expr": "$#$pos[$pos<3]",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": [
@@ -10,7 +10,25 @@
         ]
     },
     {
-        "expr": "$.$#$pos[$pos<3]^($)",
+        "expr": "$#$pos[$pos<3] = $[[0..2]]",
+        "data": [3,1,4,1,5,9],
+        "bindings": {},
+        "result": true
+    },
+    {
+        "expr": "$.$#$pos[$pos<3]",
+        "data": [3,1,4,1,5,9],
+        "bindings": {},
+        "result": [3,1,4,1,5,9]
+    },
+    {
+        "expr": "$.$#$pos[$pos<3] = $.$[[0..2]]",
+        "data": [3,1,4,1,5,9],
+        "bindings": {},
+        "result": true
+    },
+    {
+        "expr": "$#$pos[$pos<3]^($)",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": [
@@ -20,7 +38,7 @@
         ]
     },
     {
-        "expr": "$.$#$pos[$pos<3]^(>$)",
+        "expr": "$#$pos[$pos<3]^(>$)",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": [
@@ -30,7 +48,7 @@
         ]
     },
     {
-        "expr": "$.$^($)#$pos[$pos<3] ",
+        "expr": "$^($)#$pos[$pos<3] ",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": [
@@ -40,35 +58,41 @@
         ]
     },
     {
-        "expr": "$.$#$pos[$pos<3][1]",
+        "expr": "$#$pos[$pos<3][1]",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": 1
     },
     {
-        "expr": "$.$#$pos[$pos<3][1][]",
+        "expr": "$#$pos[$pos<3][1][]",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": [1]
     },
     {
-        "expr": "$.$#$pos[$pos<3]^($)[-1]",
+        "expr": "$#$pos[$pos<3]^($)[-1]",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": 4
     },
     {
-        "expr": "$.$#$pos[][$pos<3]^($)[-1]",
+        "expr": "$#$pos[][$pos<3]^($)[-1]",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": [4]
     },
     {
-        "expr": "$.$#$pos[$pos<3]^($)[-1][]",
+        "expr": "$#$pos[$pos<3]^($)[-1][]",
         "data": [3,1,4,1,5,9],
         "bindings": {},
         "result": [4]
     },
+    {
+        "expr": "$[[1..4]]#$pos[$pos>=2]",
+        "data": [3,1,4,1,5,9],
+        "bindings": {},
+        "result": [1,5]
+    },
     {
         "expr": "Account.Order#$o.Product[ProductID=858383].{ 'Product': `Product Name`, 'Order Index': $o }",
         "dataset": "dataset5",