diff --git a/src/main/java/com/dashjoin/jsonata/Functions.java b/src/main/java/com/dashjoin/jsonata/Functions.java index 17fb147..db6c605 100644 --- a/src/main/java/com/dashjoin/jsonata/Functions.java +++ b/src/main/java/com/dashjoin/jsonata/Functions.java @@ -225,13 +225,13 @@ static void string(StringBuilder b, Object arg, boolean prettify, String indent) b.append('{'); if (prettify) b.append('\n'); - for (Entry e : ((Map) arg).entrySet()) { + for (Entry e : ((Map) arg).entrySet()) { if (prettify) { b.append(indent); b.append(" "); } b.append('"'); - Utils.quote(e.getKey(), b); + Utils.quote(e.getKey().toString(), b); b.append('"'); b.append(':'); if (prettify) diff --git a/src/main/java/com/dashjoin/jsonata/Jsonata.java b/src/main/java/com/dashjoin/jsonata/Jsonata.java index 5cc6a7e..fa93d18 100644 --- a/src/main/java/com/dashjoin/jsonata/Jsonata.java +++ b/src/main/java/com/dashjoin/jsonata/Jsonata.java @@ -1535,6 +1535,14 @@ static Symbol chainAST() { List args = new ArrayList<>(); args.add(lhs); args.add(func); // == [lhs, func] result = /* await */ apply(chain, args, null, environment); } else { + Object procName = getProcName(expr.rhs); + if ("each".equals(procName) && lhs instanceof List && "partial".equals(expr.rhs.type)) { + var tempLhs = (List)lhs; + lhs = new HashMap(); + for (int i = 0; i < tempLhs.size(); i++) { + ((HashMap) lhs).put(i, tempLhs.get(i)); + } + } List args = new ArrayList<>(); args.add(lhs); // == [lhs] result = /* await */ apply(func, args, null, environment); } @@ -1544,6 +1552,14 @@ static Symbol chainAST() { return result; } + String getProcName(Symbol rhs) { + Symbol procedure = rhs.procedure; + if (procedure == null) return null; + Object procName = procedure.value; + if (procName == null) return null; + return procName.toString(); + } + boolean isFunctionLike(Object o) { return Utils.isFunction(o) || Functions.isLambda(o) || (o instanceof Pattern); } @@ -1755,7 +1771,7 @@ Jsonata getPerThreadInstance() { List _res = new ArrayList<>(); for (String s : (List)validatedArgs) { //System.err.println("PAT "+proc+" input "+s); - if (((Pattern)proc).matcher(s).find()) { + if (s != null && ((Pattern)proc).matcher(s).find()) { //System.err.println("MATCH"); _res.add(s); } @@ -1821,7 +1837,7 @@ Object evaluateLambda(Symbol expr, Object input, Frame environment) { var evaluatedArgs = new ArrayList<>(); for(var ii = 0; ii < expr.arguments.size(); ii++) { var arg = expr.arguments.get(ii); - if (arg.type.equals("operator") && (arg.value.equals("?"))) { + if (arg.type.equals("operator") && (arg.value.toString().equals("?"))) { evaluatedArgs.add(arg); } else { evaluatedArgs.add(/* await */ evaluate(arg, input, environment)); @@ -1910,7 +1926,7 @@ Object partialApplyProcedure(Symbol proc, List args) { for (var param : proc.arguments) { // proc.arguments.forEach(Object (param, index) { Object arg = index $each(?, function($v) { $v })"); + Object evaluate = expression.evaluate("{}"); + Assertions.assertNull(evaluate); + } + + @Test + public void testEachArrayWithData() { + var expression = Jsonata.jsonata("[123, 321] ~> $each(?, function($v) { $v })"); + Object evaluate = expression.evaluate("{}"); + Assertions.assertInstanceOf(List.class, evaluate); + List expected = List.of(123, 321); + Assertions.assertEquals(expected, evaluate); + } + + @Test + public void testMapInPipe() throws IOException { + Object data = JsonUtils.readJsonFromResources("map_in_pipe/input.json"); + Object answer = JsonUtils.readJsonFromResources("map_in_pipe/answer.json"); + var expression = Jsonata.jsonata("$sift($.buildings, function($v, $k) { $k ~> /o/ and $v.presentation.*.widget})" + + " ~> $each(?, function($v, $key) {{ $key: $sift($v.presentation, function($v, $k){ $v.widget }) }})" + + " ~> $map(?, function($v){($v.*)})"); + Object evaluate = expression.evaluate(data); + Assertions.assertInstanceOf(List.class, evaluate); + Assertions.assertEquals(answer, evaluate); + } } diff --git a/src/test/java/com/dashjoin/jsonata/Generate.java b/src/test/java/com/dashjoin/jsonata/Generate.java index 772a984..53a22e8 100644 --- a/src/test/java/com/dashjoin/jsonata/Generate.java +++ b/src/test/java/com/dashjoin/jsonata/Generate.java @@ -37,7 +37,7 @@ public static void main(String[] args) throws IOException { String name = cas.getName().substring(0, cas.getName().length() - 5); String jname = name.replace('-', '_'); - Object jsonCase = new JsonataTest().readJson(cas.getAbsolutePath()); + Object jsonCase = JsonUtils.readJson(cas.getAbsolutePath()); if (jsonCase instanceof List) { for (int i=0; i<((List)jsonCase).size(); i++) { b.append("// " + s(((Map)((List) jsonCase).get(i)).get("expr"))+"\n"); diff --git a/src/test/java/com/dashjoin/jsonata/JsonUtils.java b/src/test/java/com/dashjoin/jsonata/JsonUtils.java new file mode 100644 index 0000000..9ccc90b --- /dev/null +++ b/src/test/java/com/dashjoin/jsonata/JsonUtils.java @@ -0,0 +1,34 @@ +package com.dashjoin.jsonata; + +import com.dashjoin.jsonata.json.Json; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.exc.StreamReadException; +import com.fasterxml.jackson.databind.DatabindException; +import com.fasterxml.jackson.databind.JsonMappingException; + +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; + +public class JsonUtils { + + static Charset utf8Charset = Charset.forName("UTF-8"); + + static Object toJson(String jsonStr) throws JsonMappingException, JsonProcessingException { + return Json.parseJson(jsonStr); + } + + static Object readJson(String name) throws StreamReadException, DatabindException, IOException { + return Json.parseJson(new FileReader(name, utf8Charset)); + } + + static Object readJsonFromResources(String name) throws IOException { + InputStream resourceAsStream = JsonUtils.class.getClassLoader().getResourceAsStream(name); + if (resourceAsStream == null) { + throw new RuntimeException("Resource not found: " + name); + } + return Json.parseJson(new InputStreamReader(resourceAsStream, utf8Charset)); + } +} diff --git a/src/test/java/com/dashjoin/jsonata/JsonataTest.java b/src/test/java/com/dashjoin/jsonata/JsonataTest.java index 7c61eda..2dbba08 100644 --- a/src/test/java/com/dashjoin/jsonata/JsonataTest.java +++ b/src/test/java/com/dashjoin/jsonata/JsonataTest.java @@ -102,20 +102,6 @@ ObjectMapper getObjectMapper() { return om; } - Object toJson(String jsonStr) throws JsonMappingException, JsonProcessingException { - //ObjectMapper om = getObjectMapper(); - //Object json = om.readValue(jsonStr, Object.class); - Object json = Json.parseJson(jsonStr); - return json; - } - - Object readJson(String name) throws StreamReadException, DatabindException, IOException { - //ObjectMapper om = getObjectMapper(); - //Object json = om.readValue(new java.io.FileReader(name, Charset.forName("UTF-8")), Object.class); - - Object json = Json.parseJson(new java.io.FileReader(name, Charset.forName("UTF-8"))); - return json; - } @Test public void testSimple() { @@ -125,7 +111,7 @@ public void testSimple() { @Test public void testPath() throws Exception { - Object data = readJson("jsonata/test/test-suite/datasets/dataset0.json"); + Object data = JsonUtils.readJson("jsonata/test/test-suite/datasets/dataset0.json"); System.out.println(data); testExpr("foo.bar", data, null, 42,null); } @@ -146,7 +132,7 @@ public void runCase(String name) throws Exception { } public void runSubCase(String name, int subNr) throws Exception { - List cases = (List)readJson(name); + List cases = (List)JsonUtils.readJson(name); if (!runTestCase(name+"_"+subNr, (Map) cases.get(subNr))) throw new Exception(); } @@ -158,7 +144,7 @@ boolean runTestSuite(String name) throws Exception { boolean success = true; - Object testCase = readJson(name); + Object testCase = JsonUtils.readJson(name); if (testCase instanceof List) { // some cases contain a list of test cases // loop over the case definitions @@ -264,7 +250,7 @@ boolean runTestCase(String name, Map testDef) throws Exception { Object data = testDef.get("data"); if (data==null && dataset!=null) - data = readJson("jsonata/test/test-suite/datasets/"+dataset+".json"); + data = JsonUtils.readJson("jsonata/test/test-suite/datasets/"+dataset+".json"); TestOverride to = getOverrideForTest(name); if (to!=null) { diff --git a/src/test/resources/map_in_pipe/answer.json b/src/test/resources/map_in_pipe/answer.json new file mode 100644 index 0000000..5c5e15a --- /dev/null +++ b/src/test/resources/map_in_pipe/answer.json @@ -0,0 +1,30 @@ +[ + { + "first": { + "widget": { + "data": "home widget" + } + } + }, + { + "first": { + "widget": { + "data": "work widget" + } + } + }, + { + "first": { + "widget": { + "data": "old widget" + } + } + }, + { + "first": { + "widget": { + "data": "operation widget" + } + } + } +] \ No newline at end of file diff --git a/src/test/resources/map_in_pipe/input.json b/src/test/resources/map_in_pipe/input.json new file mode 100644 index 0000000..5359645 --- /dev/null +++ b/src/test/resources/map_in_pipe/input.json @@ -0,0 +1,58 @@ +{ + "buildings": { + "home": { + "address": "home address", + "period": "11 month on 12", + "presentation": { + "first": { + "widget": { + "data": "home widget" + } + } + } + }, + "work": { + "address": "work address", + "presentation": { + "first": { + "widget": { + "data": "work widget" + } + } + } + }, + "vacancy": { + "address": "vacancy address", + "period": "1 month on 12", + "presentation": { + "first": { + "widget": { + "data": "vacancy widget" + } + } + } + }, + "old": { + "address": "old address", + "period": "2 month on 12", + "presentation": { + "first": { + "widget": { + "data": "old widget" + } + } + } + }, + "operation": { + "address": "operation address", + "period": "3 month on 12", + "presentation": { + "first": { + "widget": { + "data": "operation widget" + } + } + } + } + } +} \ No newline at end of file