From 953acdf42e922eef53f48a1b5a998ae9311984ad Mon Sep 17 00:00:00 2001 From: Philipp Ossler Date: Wed, 20 Sep 2023 11:38:07 +0200 Subject: [PATCH 1/3] build: Dump feel-engine to 1.17.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84c59714..9b92680e 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ 17 - 1.16.1 + 1.17.0 3.1.3 From 24e309f297a0a7ff79ff093e14821cb925baf065 Mon Sep 17 00:00:00 2001 From: Philipp Ossler Date: Wed, 20 Sep 2023 11:38:39 +0200 Subject: [PATCH 2/3] feat: Expose evaluation failures --- .../api/FeelEvaluationController.java | 42 +++++++++++++++++-- .../dto/FeelEvaluationResponse.java | 12 ++++++ .../playground/dto/FeelEvaluationWarning.java | 35 ++++++++++++++++ .../sevice/FeelEvaluationService.java | 37 ++++++---------- 4 files changed, 98 insertions(+), 28 deletions(-) create mode 100644 src/main/java/org/camunda/feel/playground/dto/FeelEvaluationWarning.java diff --git a/src/main/java/org/camunda/feel/playground/api/FeelEvaluationController.java b/src/main/java/org/camunda/feel/playground/api/FeelEvaluationController.java index 5841f588..251f563d 100644 --- a/src/main/java/org/camunda/feel/playground/api/FeelEvaluationController.java +++ b/src/main/java/org/camunda/feel/playground/api/FeelEvaluationController.java @@ -1,7 +1,9 @@ package org.camunda.feel.playground.api; +import org.camunda.feel.api.EvaluationResult; import org.camunda.feel.playground.dto.FeelEvaluationRequest; import org.camunda.feel.playground.dto.FeelEvaluationResponse; +import org.camunda.feel.playground.dto.FeelEvaluationWarning; import org.camunda.feel.playground.dto.FeelUnaryTestsEvaluationRequest; import org.camunda.feel.playground.sevice.FeelEvaluationService; import org.camunda.feel.playground.sevice.TrackingService; @@ -15,6 +17,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.List; + @RestController @RequestMapping("/api/v1") @CrossOrigin() @@ -39,8 +44,7 @@ public ResponseEntity evaluate( try { final var result = evaluationService.evaluate(request.expression, request.context); - - return new ResponseEntity<>(FeelEvaluationResponse.withResult(result), HttpStatus.OK); + return createEvaluationResponse(result); } catch (Exception e) { return new ResponseEntity<>(FeelEvaluationResponse.withError(e.getMessage()), HttpStatus.OK); @@ -50,6 +54,38 @@ public ResponseEntity evaluate( } } + private static ResponseEntity createEvaluationResponse( + EvaluationResult result) { + final var warnings = collectEvaluationWarnings(result); + + if (result.isSuccess()) { + final var response = FeelEvaluationResponse.withResult(result.result()); + response.setWarnings(warnings); + return new ResponseEntity<>(response, HttpStatus.OK); + + } else { + final var failureMessage = result.failure().message(); + final var response = FeelEvaluationResponse.withError(failureMessage); + response.setWarnings(warnings); + return new ResponseEntity<>(response, HttpStatus.OK); + } + } + + private static List collectEvaluationWarnings(EvaluationResult result) { + final var warnings = new ArrayList(); + result + .suppressedFailures() + .foreach( + failure -> { + final var warning = + FeelEvaluationWarning.of( + failure.failureType().toString(), failure.failureMessage()); + warnings.add(warning); + return null; + }); + return warnings; + } + @PostMapping("/feel-unary-tests/evaluate") public ResponseEntity evaluateUnaryTests( @RequestBody FeelUnaryTestsEvaluationRequest request) { @@ -61,7 +97,7 @@ public ResponseEntity evaluateUnaryTests( evaluationService.evaluateUnaryTests( request.expression, request.inputValue, request.context); - return new ResponseEntity<>(FeelEvaluationResponse.withResult(result), HttpStatus.OK); + return createEvaluationResponse(result); } catch (Exception e) { return new ResponseEntity<>(FeelEvaluationResponse.withError(e.getMessage()), HttpStatus.OK); diff --git a/src/main/java/org/camunda/feel/playground/dto/FeelEvaluationResponse.java b/src/main/java/org/camunda/feel/playground/dto/FeelEvaluationResponse.java index a333197b..073f5f8e 100644 --- a/src/main/java/org/camunda/feel/playground/dto/FeelEvaluationResponse.java +++ b/src/main/java/org/camunda/feel/playground/dto/FeelEvaluationResponse.java @@ -7,11 +7,15 @@ */ package org.camunda.feel.playground.dto; +import java.util.List; + public final class FeelEvaluationResponse { public Object result; public String error; + public List warnings; + public Object getResult() { return result; } @@ -28,6 +32,14 @@ public void setError(final String error) { this.error = error; } + public List getWarnings() { + return warnings; + } + + public void setWarnings(List warnings) { + this.warnings = warnings; + } + public static FeelEvaluationResponse withResult(Object result) { final var response = new FeelEvaluationResponse(); response.setResult(result); diff --git a/src/main/java/org/camunda/feel/playground/dto/FeelEvaluationWarning.java b/src/main/java/org/camunda/feel/playground/dto/FeelEvaluationWarning.java new file mode 100644 index 00000000..caa1bb11 --- /dev/null +++ b/src/main/java/org/camunda/feel/playground/dto/FeelEvaluationWarning.java @@ -0,0 +1,35 @@ +package org.camunda.feel.playground.dto; + +public final class FeelEvaluationWarning { + + public String type; + public String message; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public static FeelEvaluationWarning of(String type, String message) { + final var warning = new FeelEvaluationWarning(); + warning.type = type; + warning.message = message; + return warning; + } + + @Override + public String toString() { + return "FeelEvaluationWarning{" + "type='" + type + '\'' + ", message='" + message + '\'' + '}'; + } +} diff --git a/src/main/java/org/camunda/feel/playground/sevice/FeelEvaluationService.java b/src/main/java/org/camunda/feel/playground/sevice/FeelEvaluationService.java index d98c376f..101fdf91 100644 --- a/src/main/java/org/camunda/feel/playground/sevice/FeelEvaluationService.java +++ b/src/main/java/org/camunda/feel/playground/sevice/FeelEvaluationService.java @@ -7,43 +7,30 @@ */ package org.camunda.feel.playground.sevice; -import java.util.HashMap; import java.util.Map; import org.camunda.feel.FeelEngine; +import org.camunda.feel.api.EvaluationResult; +import org.camunda.feel.api.FeelEngineApi; import org.camunda.feel.impl.JavaValueMapper; import org.springframework.stereotype.Component; @Component public final class FeelEvaluationService { - private final FeelEngine feelEngine = - new FeelEngine.Builder().customValueMapper(new JavaValueMapper()).build(); + private final FeelEngineApi feelEngineApi = buildFeelEngine(); - public Object evaluate(String expression, Map context) { - final var evaluationResult = feelEngine.evalExpression(expression, context); - - if (evaluationResult.isRight()) { - return evaluationResult.right().get(); + private FeelEngineApi buildFeelEngine() { + final var feelEngine = + new FeelEngine.Builder().customValueMapper(new JavaValueMapper()).build(); + return new FeelEngineApi(feelEngine); + } - } else { - final var failure = evaluationResult.left().get(); - throw new RuntimeException(failure.message()); - } + public EvaluationResult evaluate(String expression, Map context) { + return feelEngineApi.evaluateExpression(expression, context); } - public Object evaluateUnaryTests( + public EvaluationResult evaluateUnaryTests( String expression, Object inputValue, Map context) { - final var contextWithInput = new HashMap<>(context); - contextWithInput.put("cellInput", inputValue); // FeelEngine.UnaryTests.defaultInputVariable() - - final var evaluationResult = feelEngine.evalUnaryTests(expression, contextWithInput); - - if (evaluationResult.isRight()) { - return evaluationResult.right().get(); - - } else { - final var failure = evaluationResult.left().get(); - throw new RuntimeException(failure.message()); - } + return feelEngineApi.evaluateUnaryTests(expression, inputValue, context); } } From 44578190957399d7ef5fc87f9be69289806286a5 Mon Sep 17 00:00:00 2001 From: Philipp Ossler Date: Wed, 20 Sep 2023 15:44:23 +0200 Subject: [PATCH 3/3] test: Adjust test cases --- .../camunda/feel/playground/FeelApiTest.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/camunda/feel/playground/FeelApiTest.java b/src/test/java/org/camunda/feel/playground/FeelApiTest.java index 82308b65..6f555d59 100644 --- a/src/test/java/org/camunda/feel/playground/FeelApiTest.java +++ b/src/test/java/org/camunda/feel/playground/FeelApiTest.java @@ -65,17 +65,30 @@ void shouldReturnContext() throws Exception { .andExpect(content().json("{'result': {'x': 1}}")); } - @Test + @Test + void shouldReturnEvaluationWarnings() throws Exception { + mvc.perform( + post("/api/v1/feel/evaluate") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"expression\": \"x\", \"context\": {}}")) + .andExpect(status().isOk()) + .andExpect(content().json( + "{'result': null, 'warnings': [{'type': \"NO_VARIABLE_FOUND\", 'message': \"No variable found with name 'x'\"}]}" + )); + } + + + @Test void shouldReturnEvaluationFailure() throws Exception { mvc.perform( post("/api/v1/feel/evaluate") .contentType(MediaType.APPLICATION_JSON) - .content("{\"expression\": \"x\", \"context\": {}}")) + .content("{\"expression\": \"assert(x, x != null)\", \"context\": {}}")) .andExpect(status().isOk()) .andExpect( content() .json( - "{'error': \"failed to evaluate expression 'x': no variable found for name 'x'\"}")); + "{'error': \"Assertion failure on evaluate the expression 'assert(x, x != null)': The condition is not fulfilled\"}")); } @Test