diff --git a/core/src/main/java/io/kestra/core/runners/pebble/Extension.java b/core/src/main/java/io/kestra/core/runners/pebble/Extension.java index 24d3b34889f..6cc3d5ea31d 100644 --- a/core/src/main/java/io/kestra/core/runners/pebble/Extension.java +++ b/core/src/main/java/io/kestra/core/runners/pebble/Extension.java @@ -91,6 +91,7 @@ public Map getFilters() { filters.put("startsWith", new StartsWithFilter()); filters.put("endsWith", new EndsWithFilter()); filters.put("values", new ValuesFilter()); + filters.put("toIon", new ToIonFilter()); return filters; } diff --git a/core/src/main/java/io/kestra/core/runners/pebble/filters/ToIonFilter.java b/core/src/main/java/io/kestra/core/runners/pebble/filters/ToIonFilter.java new file mode 100644 index 00000000000..6495d29e1de --- /dev/null +++ b/core/src/main/java/io/kestra/core/runners/pebble/filters/ToIonFilter.java @@ -0,0 +1,34 @@ +package io.kestra.core.runners.pebble.filters; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.kestra.core.serializers.JacksonMapper; +import io.pebbletemplates.pebble.error.PebbleException; +import io.pebbletemplates.pebble.extension.Filter; +import io.pebbletemplates.pebble.template.EvaluationContext; +import io.pebbletemplates.pebble.template.PebbleTemplate; + +import java.util.List; +import java.util.Map; + +public class ToIonFilter implements Filter { + private static final ObjectMapper MAPPER = JacksonMapper.ofIon(); + + @Override + public List getArgumentNames() { + return null; + } + + @Override + public Object apply(Object input, Map args, PebbleTemplate self, EvaluationContext context, int lineNumber) throws PebbleException { + if (input == null) { + return "null"; + } + + try { + return MAPPER.writeValueAsString(input); + } catch (JsonProcessingException e) { + throw new PebbleException(e, "Unable to transform to ion value '" + input + "' with type '" + input.getClass().getName() + "'", lineNumber, self.getName()); + } + } +} diff --git a/core/src/test/java/io/kestra/core/runners/pebble/filters/ToIonFilterTest.java b/core/src/test/java/io/kestra/core/runners/pebble/filters/ToIonFilterTest.java new file mode 100644 index 00000000000..2ee1f826f67 --- /dev/null +++ b/core/src/test/java/io/kestra/core/runners/pebble/filters/ToIonFilterTest.java @@ -0,0 +1,87 @@ +package io.kestra.core.runners.pebble.filters; + +import com.google.common.collect.ImmutableMap; +import io.kestra.core.exceptions.IllegalVariableEvaluationException; +import io.kestra.core.runners.VariableRenderer; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.*; + +class ToIonFilterTest { + @Inject + VariableRenderer variableRenderer; + + @Test + void toIonFilter() throws IllegalVariableEvaluationException { + ZonedDateTime date = ZonedDateTime.parse("2013-09-08T16:19:00+02").withZoneSameLocal(ZoneId.systemDefault()); + + ImmutableMap vars = ImmutableMap.of( + "vars", ImmutableMap.of("second", Map.of( + "string", "string", + "int", 1, + "float", 1.123F, + "list", Arrays.asList( + "string", + 1, + 1.123F + ), + "bool", true, + "date", date, + "map", Map.of( + "string", "string", + "int", 1, + "float", 1.123F + ) + )) + ); + + String render = variableRenderer.render("{{ vars.second.string | toIon }}", vars); + assertThat(render, is("\"string\"")); + + render = variableRenderer.render("{{ vars.second.int | toIon }}", vars); + assertThat(render, is("1")); + + render = variableRenderer.render("{{ vars.second.float | toIon }}", vars); + assertThat(render, is("1.123")); + + render = variableRenderer.render("{{ vars.second.list | toIon }}", vars); + assertThat(render, is("[\"string\",1,1.123]")); + + render = variableRenderer.render("{{ vars.second.bool | toIon }}", vars); + assertThat(render, is("true")); + + render = variableRenderer.render("{{ vars.second.date | toIon }}", vars); + assertThat(render, is("\"" + date.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + "\"")); + + render = variableRenderer.render("{{ vars.second.map | toIon }}", vars); + assertThat(render, containsString("\"int\":1")); + assertThat(render, containsString("\"int\":1")); + assertThat(render, containsString("\"float\":1.123")); + assertThat(render, containsString("\"string\":\"string\"")); + assertThat(render, startsWith("{")); + assertThat(render, endsWith("}")); + + render = variableRenderer.render("{{ {\"empty_object\":{}} | toIon }}", Map.of()); + assertThat(render, is("{\"empty_object\":{}}")); + + render = variableRenderer.render("{{ null | toIon }}", Map.of()); + assertThat(render, is("null")); + } + + @Test + void exception() { + assertThrows(IllegalVariableEvaluationException.class, () -> variableRenderer.render("{{ | toIon }}", Map.of())); + + assertThrows(IllegalVariableEvaluationException.class, () -> variableRenderer.render("{{ {not: json} | toIon }}", Map.of())); + } +} \ No newline at end of file diff --git a/core/src/test/java/io/kestra/core/runners/pebble/filters/ToJsonFilterTest.java b/core/src/test/java/io/kestra/core/runners/pebble/filters/ToJsonFilterTest.java index c6e3e4b5b4c..094647feb37 100644 --- a/core/src/test/java/io/kestra/core/runners/pebble/filters/ToJsonFilterTest.java +++ b/core/src/test/java/io/kestra/core/runners/pebble/filters/ToJsonFilterTest.java @@ -24,7 +24,7 @@ class ToJsonFilterTest { VariableRenderer variableRenderer; @Test - void jsonEncodeFilter() throws IllegalVariableEvaluationException { + void toJsonFilter() throws IllegalVariableEvaluationException { ZonedDateTime date = ZonedDateTime.parse("2013-09-08T16:19:00+02").withZoneSameLocal(ZoneId.systemDefault()); ImmutableMap vars = ImmutableMap.of( @@ -95,7 +95,7 @@ void jsonFilter() throws IllegalVariableEvaluationException { )) ); - String render = variableRenderer.render("{{ vars.second.string | toJson }}", vars); + String render = variableRenderer.render("{{ vars.second.string | json }}", vars); assertThat(render, is("\"string\"")); } } diff --git a/core/src/test/java/io/kestra/core/runners/pebble/functions/FromJsonFunctionTest.java b/core/src/test/java/io/kestra/core/runners/pebble/functions/FromJsonFunctionTest.java index 2bc597adfbb..ce10c3a4139 100644 --- a/core/src/test/java/io/kestra/core/runners/pebble/functions/FromJsonFunctionTest.java +++ b/core/src/test/java/io/kestra/core/runners/pebble/functions/FromJsonFunctionTest.java @@ -18,7 +18,7 @@ class FromJsonFunctionTest { VariableRenderer variableRenderer; @Test - void jsonDecodeFunction() throws IllegalVariableEvaluationException { + void fronJsonFunction() throws IllegalVariableEvaluationException { String render = variableRenderer.render("{{ fromJson('{\"test1\": 1, \"test2\": 2, \"test3\": 3}').test1 }}", Map.of()); assertThat(render, is("1"));