Repository: jsonata-js/jsonata
Pull request #351 (2019-08-20 13:58:44)

Add $error() function.
Proposed in https://github.com/jsonata-js/jsonata/issues/167

Implementation notes:
* Used error code `D3137` for all errors thrown with this function since it was the next number in the sequence (for dynamically thrown errors from functions).
* There is no template text for this error.
* Message is optional.  Defaults to `$error() function evaluated`

coveralls: 
[![Coverage Status](https://coveralls.io/builds/25240413/badge)](https://coveralls.io/builds/25240413)

Coverage remained the same at 100.0% when pulling **fdbf8cbd26a9cd333879699631c7171628bcbd32 on elasticio:add-error-function** into **2587ffc5044dc8acbe638b35d89b7399fa170b9f on jsonata-js:master**.

andrew-coleman: I'm happy to publish a 1.6.6 release with this.  Or are you planning any more PRs soon? ;)

Patch:
diff --git a/src/functions.js b/src/functions.js
index c62f41c..a675d9f 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -1639,6 +1639,19 @@ const functions = (() => {
         return result;
     }
 
+    /**
+     *
+     * @param {string} [message] - the message to attach to the error
+     * @throws custom error with code 'D3137'
+     */
+    function error(message) {
+        throw {
+            code: "D3137",
+            stack: (new Error()).stack,
+            message: message || "$error() function evaluated"
+        };
+    }
+
     /**
      * Implements the merge sort (stable) with optional comparator function
      *
@@ -1778,7 +1791,7 @@ const functions = (() => {
         formatNumber, formatBase, number, floor, ceil, round, abs, sqrt, power, random,
         boolean, not,
         map, zip, filter, foldLeft, sift,
-        keys, lookup, append, exists, spread, merge, reverse, each, sort, shuffle,
+        keys, lookup, append, exists, spread, merge, reverse, each, error, sort, shuffle,
         base64encode, base64decode
     };
 })();
diff --git a/src/jsonata.js b/src/jsonata.js
index ac64ec8..99e6e89 100644
--- a/src/jsonata.js
+++ b/src/jsonata.js
@@ -1699,6 +1699,7 @@ var jsonata = (function() {
     staticFrame.bind('merge', defineFunction(fn.merge, '<a<o>:o>'));
     staticFrame.bind('reverse', defineFunction(fn.reverse, '<a:a>'));
     staticFrame.bind('each', defineFunction(fn.each, '<o-f:a>'));
+    staticFrame.bind('error', defineFunction(fn.error, '<s?:x>'));
     staticFrame.bind('sort', defineFunction(fn.sort, '<af?:a>'));
     staticFrame.bind('shuffle', defineFunction(fn.shuffle, '<a:a>'));
     staticFrame.bind('base64encode', defineFunction(fn.base64encode, '<s-:s>'));


Test patch:
diff --git a/test/test-suite/groups/function-error/case000.json b/test/test-suite/groups/function-error/case000.json
new file mode 100644
index 0000000..d7f7d65
--- /dev/null
+++ b/test/test-suite/groups/function-error/case000.json
@@ -0,0 +1,6 @@
+{
+    "expr": "Account.Order[0].Product[0].Price > 35 ? Account.Order[0].Product[0].Price : $error('Too Expensive')",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "D3137"
+}
diff --git a/test/test-suite/groups/function-error/case001.json b/test/test-suite/groups/function-error/case001.json
new file mode 100644
index 0000000..c95b115
--- /dev/null
+++ b/test/test-suite/groups/function-error/case001.json
@@ -0,0 +1,6 @@
+{
+    "expr": "Account.Order[0].Product[0].Price > 34 ? Account.Order[0].Product[0].Price : $error('Too Expensive')",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": 34.45
+}
diff --git a/test/test-suite/groups/function-error/case002.json b/test/test-suite/groups/function-error/case002.json
new file mode 100644
index 0000000..ae1a6c4
--- /dev/null
+++ b/test/test-suite/groups/function-error/case002.json
@@ -0,0 +1,6 @@
+{
+    "expr": "Account.Order[0].Product[0].Price > 35 ? $error('Too Expensive') : Account.Order[0].Product[0].Price",
+    "dataset": "dataset5",
+    "bindings": {},
+    "result": 34.45
+}
diff --git a/test/test-suite/groups/function-error/case003.json b/test/test-suite/groups/function-error/case003.json
new file mode 100644
index 0000000..81bd3ee
--- /dev/null
+++ b/test/test-suite/groups/function-error/case003.json
@@ -0,0 +1,6 @@
+{
+    "expr": "Account.Order[0].Product[0].Price > 34 ? $error('Too Expensive') : Account.Order[0].Product[0].Price",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "D3137"
+}
diff --git a/test/test-suite/groups/function-error/case004.json b/test/test-suite/groups/function-error/case004.json
new file mode 100644
index 0000000..786d7a3
--- /dev/null
+++ b/test/test-suite/groups/function-error/case004.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$count(Account.Order[0].Product) < 2 ? $error('Not enough products in orders')",
+    "dataset": "dataset5",
+    "bindings": {},
+    "undefinedResult": true
+}
diff --git a/test/test-suite/groups/function-error/case005.json b/test/test-suite/groups/function-error/case005.json
new file mode 100644
index 0000000..7d1a425
--- /dev/null
+++ b/test/test-suite/groups/function-error/case005.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$count(Account.Order[0].Product) < 3 ? $error('Not enough products in orders')",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "D3137"
+}
diff --git a/test/test-suite/groups/function-error/case006.json b/test/test-suite/groups/function-error/case006.json
new file mode 100644
index 0000000..3366562
--- /dev/null
+++ b/test/test-suite/groups/function-error/case006.json
@@ -0,0 +1,6 @@
+{
+    "expr": "($msg='My Message'; $error($msg); true)",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "D3137"
+}
diff --git a/test/test-suite/groups/function-error/case007.json b/test/test-suite/groups/function-error/case007.json
new file mode 100644
index 0000000..dbdfe09
--- /dev/null
+++ b/test/test-suite/groups/function-error/case007.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$error(null)",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "T0410"
+}
diff --git a/test/test-suite/groups/function-error/case008.json b/test/test-suite/groups/function-error/case008.json
new file mode 100644
index 0000000..da3de06
--- /dev/null
+++ b/test/test-suite/groups/function-error/case008.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$error(5)",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "T0410"
+}
diff --git a/test/test-suite/groups/function-error/case009.json b/test/test-suite/groups/function-error/case009.json
new file mode 100644
index 0000000..ef79f2b
--- /dev/null
+++ b/test/test-suite/groups/function-error/case009.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$error()",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "D3137"
+}
diff --git a/test/test-suite/groups/function-error/case010.json b/test/test-suite/groups/function-error/case010.json
new file mode 100644
index 0000000..6866efd
--- /dev/null
+++ b/test/test-suite/groups/function-error/case010.json
@@ -0,0 +1,6 @@
+{
+    "expr": "$error(foo)",
+    "dataset": "dataset5",
+    "bindings": {},
+    "code": "D3137"
+}