Skip to content

Commit d9a70c2

Browse files
committed
docs: Make sure the DSL documentation reflects clearly the code
Signed-off-by: Matheus André <matheusandr2@gmail.com>
1 parent ac16ede commit d9a70c2

3 files changed

Lines changed: 79 additions & 27 deletions

File tree

experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/Step.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ public <T, R> SELF exportAs(Function<T, R> function, Class<T> taskResultClass) {
156156
/**
157157
* Shapes what the task exports for downstream consumers using a context-aware filter function.
158158
*
159-
* <p>This variant provides access to both workflow and task context, allowing you to inspect
160-
* metadata when shaping the export.
159+
* <p>This variant provides access to the task result, workflow context, and task context,
160+
* allowing you to inspect metadata when shaping the export.
161161
*
162-
* @param <T> the workflow context type
162+
* @param <T> the task result type
163163
* @param <R> the export type (what gets written in the context)
164-
* @param function the filter function with workflow and task context
164+
* @param function the filter function with task result, workflow context, and task context
165165
* @return this step for method chaining
166166
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(FilterFunction)
167167
*/
@@ -177,10 +177,10 @@ public <T, R> SELF exportAs(FilterFunction<T, R> function) {
177177
* Shapes what the task exports for downstream consumers using a context-aware filter function
178178
* with explicit input type.
179179
*
180-
* @param <T> the workflow context type
180+
* @param <T> the task result type
181181
* @param <R> the export type (what gets written in the context)
182-
* @param function the filter function with workflow and task context
183-
* @param taskResultClass the class of the workflow context type
182+
* @param function the filter function with task result, workflow context, and task context
183+
* @param taskResultClass the class of the task result type
184184
* @return this step for method chaining
185185
* @see io.serverlessworkflow.fluent.func.spi.FuncTaskTransformations#exportAs(FilterFunction,
186186
* Class)
@@ -278,7 +278,7 @@ public SELF exportAs(String jqExpression) {
278278
*
279279
* <pre>{@code
280280
* agent("investmentAnalyst", analyst::analyse, InvestmentMemo.class)
281-
* .outputAs(memo -> Map.of("memo", memo))
281+
* .outputAs(taskOutput -> Map.of("memo", taskOutput))
282282
* .when(condition);
283283
* }</pre>
284284
*
@@ -318,20 +318,21 @@ public <T, R> SELF outputAs(Function<T, R> function, Class<T> taskResultClass) {
318318
* Shapes what gets written back into the workflow data document using a context-aware filter
319319
* function.
320320
*
321-
* <p>This variant provides access to both workflow and task context, allowing you to inspect
322-
* metadata, task input, and raw output when shaping the committed output.
321+
* <p>This variant provides access to the task result as the first lambda parameter, plus the
322+
* workflow and task context for metadata, task input, and raw output when shaping the committed
323+
* output.
323324
*
324325
* <p><strong>Example:</strong>
325326
*
326327
* <pre>{@code
327328
* get("fetchMarketData", "http://localhost:8081/market-data/{ticker}")
328-
* .outputAs((MarketDataSnapshot snapshot,
329+
* .outputAs((MarketDataSnapshot taskOutput,
329330
* WorkflowContextData wf,
330331
* TaskContextData task) -> {
331332
* var input = task.input().asMap().orElseThrow();
332333
* var rawBody = task.rawOutput().asText().orElseThrow();
333334
* return new InvestmentPrompt(
334-
* snapshot.ticker(),
335+
* taskOutput.ticker(),
335336
* input.get("objective").toString(),
336337
* rawBody
337338
* );
@@ -340,7 +341,7 @@ public <T, R> SELF outputAs(Function<T, R> function, Class<T> taskResultClass) {
340341
*
341342
* @param <T> the task result type
342343
* @param <R> the output type (what gets written to workflow data)
343-
* @param function the filter function with workflow and task context
344+
* @param function the filter function with task result, workflow context, and task context
344345
* @return this step for method chaining
345346
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(FilterFunction)
346347
*/
@@ -358,7 +359,7 @@ public <T, R> SELF outputAs(FilterFunction<T, R> function) {
358359
*
359360
* @param <T> the task result type
360361
* @param <R> the output type (what gets written to workflow data)
361-
* @param function the filter function with workflow and task context
362+
* @param function the filter function with task result, workflow context, and task context
362363
* @param taskResultClass the class of the task result type
363364
* @return this step for method chaining
364365
* @see io.serverlessworkflow.fluent.func.spi.FuncTransformations#outputAs(FilterFunction, Class)

experimental/lambda/src/test/java/io/serverless/workflow/impl/executors/func/FuncDSLDataFlowTransformationHelpersTest.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.function;
1919
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.input;
20-
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.output;
2120

2221
import io.serverlessworkflow.api.types.Workflow;
2322
import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder;
@@ -82,11 +81,13 @@ void test_input_with_outputAs() {
8281
},
8382
Long.class)
8483
.outputAs(
85-
(object, workflowContext, taskContextData) -> {
86-
softly.assertThat(object).isEqualTo(15L);
84+
(Long taskOutput,
85+
WorkflowContextData workflowContext,
86+
TaskContextData taskContextData) -> {
87+
softly.assertThat(taskOutput).isEqualTo(15L);
8788
Long input = input(workflowContext, Long.class);
8889
softly.assertThat(input).isEqualTo(10L);
89-
return input + object;
90+
return input + taskOutput;
9091
},
9192
Long.class))
9293
.build();
@@ -119,10 +120,9 @@ void test_output_with_exportAs() {
119120
},
120121
Long.class)
121122
.exportAs(
122-
(Long object,
123+
(Long taskOutput,
123124
WorkflowContextData workflowContext,
124125
TaskContextData taskContextData) -> {
125-
Long taskOutput = output(taskContextData, Long.class);
126126
softly.assertThat(taskOutput).isEqualTo(15L);
127127
return taskOutput * 2;
128128
}))
@@ -138,6 +138,53 @@ void test_output_with_exportAs() {
138138
softly.assertAll();
139139
}
140140

141+
@Test
142+
void test_output_with_outputAs_and_exportAs() {
143+
144+
SoftAssertions softly = new SoftAssertions();
145+
146+
Workflow workflow =
147+
FuncWorkflowBuilder.workflow("enrichOutputWithOutputAsAndExportAsTest")
148+
.tasks(
149+
function(
150+
"add5",
151+
(Long input) -> {
152+
softly.assertThat(input).isEqualTo(10L);
153+
return input + 5;
154+
},
155+
Long.class)
156+
.outputAs(
157+
(Long taskOutput) -> {
158+
softly.assertThat(taskOutput).isEqualTo(15L);
159+
return taskOutput * 2;
160+
})
161+
.exportAs(
162+
(Long taskOutput,
163+
WorkflowContextData workflowContext,
164+
TaskContextData taskContextData) -> {
165+
softly.assertThat(taskOutput).isEqualTo(30L);
166+
softly
167+
.assertThat(taskContextData.output().asNumber().orElseThrow())
168+
.isEqualTo(30L);
169+
return taskOutput;
170+
}))
171+
.build();
172+
173+
try (WorkflowApplication app = WorkflowApplication.builder().build()) {
174+
WorkflowDefinition def = app.workflowDefinition(workflow);
175+
WorkflowModel model = def.instance(10L).start().join();
176+
Number number = model.asNumber().orElseThrow();
177+
softly.assertThat(number.longValue()).isEqualTo(30L);
178+
179+
WorkflowInstance instance = def.instance(10L);
180+
instance.start().join();
181+
Number contextNumber = instance.context().asNumber().orElseThrow();
182+
softly.assertThat(contextNumber.longValue()).isEqualTo(30L);
183+
}
184+
185+
softly.assertAll();
186+
}
187+
141188
@Test
142189
void test_input_with_inputFrom_fluent_way() {
143190
SoftAssertions softly = new SoftAssertions();
@@ -178,10 +225,9 @@ void test_input_with_exportAs() {
178225
},
179226
Long.class)
180227
.exportAs(
181-
(Long object,
228+
(Long taskOutput,
182229
WorkflowContextData workflowContext,
183230
TaskContextData taskContextData) -> {
184-
Long taskOutput = output(taskContextData, Long.class);
185231
softly.assertThat(taskOutput).isEqualTo(15L);
186232
Long input = input(workflowContext, Long.class);
187233
softly.assertThat(input).isEqualTo(10L);

impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowUtils.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,16 @@ public static Optional<WorkflowFilter> buildWorkflowFilter(WorkflowApplication a
8282
}
8383

8484
public static Optional<WorkflowFilter> buildWorkflowFilter(WorkflowApplication app, ExportAs as) {
85-
return as != null
86-
? Optional.of(
87-
buildFilterFromStrObject(
88-
app.expressionFactory(), app.contextFactory(), as.getString(), as.getObject()))
89-
: Optional.empty();
85+
if (as == null) {
86+
return Optional.empty();
87+
}
88+
WorkflowFilter filter =
89+
buildFilterFromStrObject(
90+
app.expressionFactory(), app.contextFactory(), as.getString(), as.getObject());
91+
if (as.getString() == null && as.getObject() != null) {
92+
return Optional.of((w, t, m) -> filter.apply(w, t, t.output()));
93+
}
94+
return Optional.of(filter);
9095
}
9196

9297
public static WorkflowFilter buildWorkflowFilter(WorkflowApplication app, Object obj) {

0 commit comments

Comments
 (0)