Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,12 @@ public <T, R> SELF exportAs(Function<T, R> function, Class<T> taskResultClass) {
/**
* Shapes what the task exports for downstream consumers using a context-aware filter function.
*
* <p>This variant provides access to both workflow and task context, allowing you to inspect
* metadata when shaping the export.
* <p>This variant provides access to the task result, workflow context, and task context,
* allowing you to inspect metadata when shaping the export.
*
* @param <T> the workflow context type
* @param <T> the task result type
* @param <R> the export type (what gets written in the context)
* @param function the filter function with workflow and task context
* @param function the filter function with task result, workflow context, and task context
* @return this step for method chaining
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(FilterFunction)
*/
Expand All @@ -177,10 +177,10 @@ public <T, R> SELF exportAs(FilterFunction<T, R> function) {
* Shapes what the task exports for downstream consumers using a context-aware filter function
* with explicit input type.
*
* @param <T> the workflow context type
* @param <T> the task result type
* @param <R> the export type (what gets written in the context)
* @param function the filter function with workflow and task context
* @param taskResultClass the class of the workflow context type
* @param function the filter function with task result, workflow context, and task context
* @param taskResultClass the class of the task result type
* @return this step for method chaining
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(FilterFunction,
* Class)
Expand Down Expand Up @@ -278,7 +278,7 @@ public SELF exportAs(String jqExpression) {
*
* <pre>{@code
* agent("investmentAnalyst", analyst::analyse, InvestmentMemo.class)
* .outputAs(memo -> Map.of("memo", memo))
* .outputAs(taskOutput -> Map.of("memo", taskOutput))
* .when(condition);
* }</pre>
*
Expand Down Expand Up @@ -318,20 +318,21 @@ public <T, R> SELF outputAs(Function<T, R> function, Class<T> taskResultClass) {
* Shapes what gets written back into the workflow data document using a context-aware filter
* function.
*
* <p>This variant provides access to both workflow and task context, allowing you to inspect
* metadata, task input, and raw output when shaping the committed output.
* <p>This variant provides access to the task result as the first lambda parameter, plus the
* workflow and task context for metadata, task input, and raw output when shaping the committed
* output.
Comment thread
matheusandre1 marked this conversation as resolved.
*
* <p><strong>Example:</strong>
*
* <pre>{@code
* get("fetchMarketData", "http://localhost:8081/market-data/{ticker}")
* .outputAs((MarketDataSnapshot snapshot,
* .outputAs((MarketDataSnapshot taskOutput,
* WorkflowContextData wf,
* TaskContextData task) -> {
* var input = task.input().asMap().orElseThrow();
* var rawBody = task.rawOutput().asText().orElseThrow();
* return new InvestmentPrompt(
* snapshot.ticker(),
* taskOutput.ticker(),
* input.get("objective").toString(),
* rawBody
* );
Expand All @@ -340,7 +341,7 @@ public <T, R> SELF outputAs(Function<T, R> function, Class<T> taskResultClass) {
*
* @param <T> the task result type
* @param <R> the output type (what gets written to workflow data)
* @param function the filter function with workflow and task context
* @param function the filter function with task result, workflow context, and task context
* @return this step for method chaining
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(FilterFunction)
*/
Expand All @@ -358,7 +359,7 @@ public <T, R> SELF outputAs(FilterFunction<T, R> function) {
*
* @param <T> the task result type
* @param <R> the output type (what gets written to workflow data)
* @param function the filter function with workflow and task context
* @param function the filter function with task result, workflow context, and task context
* @param taskResultClass the class of the task result type
* @return this step for method chaining
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(FilterFunction, Class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.function;
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.input;
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.output;

import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder;
Expand Down Expand Up @@ -82,11 +81,13 @@ void test_input_with_outputAs() {
},
Long.class)
.outputAs(
(object, workflowContext, taskContextData) -> {
softly.assertThat(object).isEqualTo(15L);
(Long taskOutput,
WorkflowContextData workflowContext,
TaskContextData taskContextData) -> {
softly.assertThat(taskOutput).isEqualTo(15L);
Long input = input(workflowContext, Long.class);
softly.assertThat(input).isEqualTo(10L);
return input + object;
return input + taskOutput;
},
Long.class))
.build();
Expand Down Expand Up @@ -119,10 +120,9 @@ void test_output_with_exportAs() {
},
Long.class)
.exportAs(
(Long object,
(Long taskOutput,
WorkflowContextData workflowContext,
TaskContextData taskContextData) -> {
Long taskOutput = output(taskContextData, Long.class);
softly.assertThat(taskOutput).isEqualTo(15L);
return taskOutput * 2;
Comment thread
matheusandre1 marked this conversation as resolved.
}))
Comment thread
matheusandre1 marked this conversation as resolved.
Expand All @@ -138,6 +138,53 @@ void test_output_with_exportAs() {
softly.assertAll();
}

@Test
void test_output_with_outputAs_and_exportAs() {

SoftAssertions softly = new SoftAssertions();

Workflow workflow =
FuncWorkflowBuilder.workflow("enrichOutputWithOutputAsAndExportAsTest")
.tasks(
function(
"add5",
(Long input) -> {
softly.assertThat(input).isEqualTo(10L);
return input + 5;
},
Long.class)
.outputAs(
(Long taskOutput) -> {
softly.assertThat(taskOutput).isEqualTo(15L);
return taskOutput * 2;
})
.exportAs(
(Long taskOutput,
WorkflowContextData workflowContext,
TaskContextData taskContextData) -> {
softly.assertThat(taskOutput).isEqualTo(30L);
softly
.assertThat(taskContextData.output().asNumber().orElseThrow())
.isEqualTo(30L);
return taskOutput;
}))
.build();

try (WorkflowApplication app = WorkflowApplication.builder().build()) {
WorkflowDefinition def = app.workflowDefinition(workflow);
WorkflowModel model = def.instance(10L).start().join();
Number number = model.asNumber().orElseThrow();
softly.assertThat(number.longValue()).isEqualTo(30L);

WorkflowInstance instance = def.instance(10L);
instance.start().join();
Number contextNumber = instance.context().asNumber().orElseThrow();
softly.assertThat(contextNumber.longValue()).isEqualTo(30L);
}

softly.assertAll();
}

@Test
void test_input_with_inputFrom_fluent_way() {
SoftAssertions softly = new SoftAssertions();
Expand Down Expand Up @@ -178,10 +225,9 @@ void test_input_with_exportAs() {
},
Long.class)
.exportAs(
(Long object,
(Long taskOutput,
WorkflowContextData workflowContext,
TaskContextData taskContextData) -> {
Long taskOutput = output(taskContextData, Long.class);
softly.assertThat(taskOutput).isEqualTo(15L);
Long input = input(workflowContext, Long.class);
softly.assertThat(input).isEqualTo(10L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,16 @@ public static Optional<WorkflowFilter> buildWorkflowFilter(WorkflowApplication a
}

public static Optional<WorkflowFilter> buildWorkflowFilter(WorkflowApplication app, ExportAs as) {
return as != null
? Optional.of(
buildFilterFromStrObject(
app.expressionFactory(), app.contextFactory(), as.getString(), as.getObject()))
: Optional.empty();
if (as == null) {
return Optional.empty();
}
WorkflowFilter filter =
buildFilterFromStrObject(
app.expressionFactory(), app.contextFactory(), as.getString(), as.getObject());
if (as.getString() == null && as.getObject() != null) {
return Optional.of((w, t, m) -> filter.apply(w, t, t.output()));
}
return Optional.of(filter);
}

public static WorkflowFilter buildWorkflowFilter(WorkflowApplication app, Object obj) {
Expand Down
Loading