Skip to content

Commit 7f053c4

Browse files
committed
feat: add sub worflows run on FuncDSL
Signed-off-by: Matheus Andre <matheusandr2@gmail.com>
1 parent 219fabc commit 7f053c4

5 files changed

Lines changed: 170 additions & 22 deletions

File tree

‎experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncDoTaskBuilder.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,16 @@ public FuncDoTaskBuilder workflow(String name, Consumer<WorkflowTaskBuilder> ite
103103
this.listBuilder().workflow(name, itemsConfigurer);
104104
return this;
105105
}
106+
107+
@Override
108+
public FuncDoTaskBuilder subflow(String name, Consumer<WorkflowTaskBuilder> itemsConfigurer) {
109+
this.listBuilder().subflow(name, itemsConfigurer);
110+
return this;
111+
}
112+
113+
@Override
114+
public FuncDoTaskBuilder subflow(Consumer<WorkflowTaskBuilder> itemsConfigurer) {
115+
this.listBuilder().subflow(itemsConfigurer);
116+
return this;
117+
}
106118
}

‎experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/FuncTaskItemListBuilder.java‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,15 @@ public FuncTaskItemListBuilder workflow(
169169
}
170170
return addTaskItem(taskItems.get(0));
171171
}
172+
173+
@Override
174+
public FuncTaskItemListBuilder subflow(
175+
String name, Consumer<WorkflowTaskBuilder> itemsConfigurer) {
176+
return this.workflow(name, itemsConfigurer);
177+
}
178+
179+
@Override
180+
public FuncTaskItemListBuilder subflow(Consumer<WorkflowTaskBuilder> itemsConfigurer) {
181+
return this.workflow(itemsConfigurer);
182+
}
172183
}

‎experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/dsl/FuncDSL.java‎

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@
3838
import io.serverlessworkflow.fluent.spec.EventFilterBuilder;
3939
import io.serverlessworkflow.fluent.spec.ScheduleBuilder;
4040
import io.serverlessworkflow.fluent.spec.TimeoutBuilder;
41+
import io.serverlessworkflow.fluent.spec.WorkflowTaskBuilder;
4142
import io.serverlessworkflow.fluent.spec.configurers.AuthenticationConfigurer;
4243
import io.serverlessworkflow.fluent.spec.configurers.WorkflowConfigurer;
4344
import io.serverlessworkflow.fluent.spec.dsl.DSL;
4445
import io.serverlessworkflow.fluent.spec.dsl.UseSpec;
46+
import io.serverlessworkflow.fluent.spec.dsl.WorkflowSpec;
4547
import io.serverlessworkflow.impl.TaskContextData;
4648
import io.serverlessworkflow.impl.WorkflowContextData;
4749
import java.net.URI;
@@ -928,14 +930,19 @@ public static FuncTaskConfigurer switchWhen(String jqExpression, String thenTask
928930
* @return list configurer
929931
*/
930932
public static <T> FuncTaskConfigurer switchWhenOrElse(
931-
Predicate<T> pred, String thenTask, FlowDirectiveEnum otherwise, Class<T> predClass) {
933+
Predicate<T> pred,
934+
String thenTask,
935+
io.serverlessworkflow.api.types.FlowDirectiveEnum otherwise,
936+
Class<T> predClass) {
932937
return list ->
933938
list.switchCase(
934939
FuncDSL.cases(caseOf(pred, predClass).then(thenTask), caseDefault(otherwise)));
935940
}
936941

937942
public static <T> FuncTaskConfigurer switchWhenOrElse(
938-
SerializablePredicate<T> pred, String thenTask, FlowDirectiveEnum otherwise) {
943+
SerializablePredicate<T> pred,
944+
String thenTask,
945+
io.serverlessworkflow.api.types.FlowDirectiveEnum otherwise) {
939946
return switchWhenOrElse(pred, thenTask, otherwise, ReflectionUtils.inferInputType(pred));
940947
}
941948

@@ -976,7 +983,9 @@ public static <T> FuncTaskConfigurer switchWhenOrElse(
976983
* @return list configurer
977984
*/
978985
public static FuncTaskConfigurer switchWhenOrElse(
979-
String jqExpression, String thenTask, FlowDirectiveEnum otherwise) {
986+
String jqExpression,
987+
String thenTask,
988+
io.serverlessworkflow.api.types.FlowDirectiveEnum otherwise) {
980989

981990
Objects.requireNonNull(jqExpression, "jqExpression");
982991
Objects.requireNonNull(thenTask, "thenTask");
@@ -1079,22 +1088,103 @@ public static FuncTaskConfigurer set(Map<String, Object> map) {
10791088
* @param configurer configurer for the nested workflow task
10801089
* @return a {@link FuncTaskConfigurer} that adds a workflow task to the tasks list
10811090
*/
1082-
public static FuncTaskConfigurer workflowTask(WorkflowConfigurer configurer) {
1091+
/**
1092+
* Create a {@link FuncTaskConfigurer} that adds a sub-workflow call task using a {@link
1093+
* WorkflowConfigurer}.
1094+
*
1095+
* <p>
1096+
*
1097+
* <pre>{@code
1098+
* tasks(
1099+
* subflow(workflow("org.acme", "sub-workflow", "0.1.0").input(...)
1100+
* );
1101+
* }</pre>
1102+
*
1103+
* @param configurer nested workflow configurer
1104+
* @return a {@link FuncTaskConfigurer} that adds a workflow task to the tasks list
1105+
*/
1106+
public static FuncTaskConfigurer subflow(WorkflowConfigurer configurer) {
1107+
Objects.requireNonNull(configurer, "configurer");
1108+
return list -> list.subflow(configurer);
1109+
}
1110+
1111+
/**
1112+
* Create a {@link FuncTaskConfigurer} that adds a named sub-workflow call task.
1113+
*
1114+
* @param name task name
1115+
* @param configurer nested workflow configurer
1116+
* @return a {@link FuncTaskConfigurer} that adds a workflow task to the tasks list
1117+
*/
1118+
public static FuncTaskConfigurer subflow(String name, Consumer<WorkflowTaskBuilder> configurer) {
1119+
Objects.requireNonNull(name, "name");
1120+
Objects.requireNonNull(configurer, "configurer");
1121+
return list -> list.subflow(name, configurer);
1122+
}
1123+
1124+
/**
1125+
* Create a {@link FuncTaskConfigurer} that adds an unnamed sub-workflow call task.
1126+
*
1127+
* @param configurer nested workflow configurer
1128+
* @return a {@link FuncTaskConfigurer} that adds a workflow task to the tasks list
1129+
*/
1130+
public static FuncTaskConfigurer subflow(Consumer<WorkflowTaskBuilder> configurer) {
10831131
Objects.requireNonNull(configurer, "configurer");
1084-
return list -> list.workflow(configurer);
1132+
return list -> list.subflow(configurer);
1133+
}
1134+
1135+
/**
1136+
* Alias for {@link #subflow(WorkflowConfigurer)}.
1137+
*
1138+
* @param configurer nested workflow configurer
1139+
* @return a {@link FuncTaskConfigurer} that adds a workflow task to the tasks list
1140+
*/
1141+
public static FuncTaskConfigurer workflowTask(WorkflowConfigurer configurer) {
1142+
return subflow(configurer);
10851143
}
10861144

10871145
/**
10881146
* Create a {@link FuncTaskConfigurer} that adds a workflow subflow task.
10891147
*
10901148
* @param configurer configurer for the nested workflow task
10911149
* @return a {@link FuncTaskConfigurer} that adds a workflow task to the tasks list
1092-
* @deprecated use {@link #workflowTask(WorkflowConfigurer)} to avoid ambiguity with spec-side
1093-
* workflow factory methods
1150+
* @deprecated use {@link #subflow(WorkflowConfigurer)} to avoid ambiguity with spec-side factory
1151+
* methods
10941152
*/
10951153
@Deprecated
10961154
public static FuncTaskConfigurer workflow(WorkflowConfigurer configurer) {
1097-
return workflowTask(configurer);
1155+
return subflow(configurer);
1156+
}
1157+
1158+
/**
1159+
* Create a new {@link WorkflowSpec} to be used as a factory for workflow definitions.
1160+
*
1161+
* @param namespace workflow namespace
1162+
* @param name workflow name
1163+
* @param version workflow version
1164+
* @return a new {@link WorkflowSpec} instance
1165+
*/
1166+
public static WorkflowSpec workflow(String namespace, String name, String version) {
1167+
return DSL.workflow(namespace, name, version);
1168+
}
1169+
1170+
/**
1171+
* Create a new {@link WorkflowSpec} to be used as a factory for workflow definitions.
1172+
*
1173+
* @param namespace workflow namespace
1174+
* @param name workflow name
1175+
* @return a new {@link WorkflowSpec} instance
1176+
*/
1177+
public static WorkflowSpec workflow(String namespace, String name) {
1178+
return DSL.workflow(namespace, name);
1179+
}
1180+
1181+
/**
1182+
* Create a new {@link WorkflowSpec} to be used as a factory for workflow definitions.
1183+
*
1184+
* @return a new {@link WorkflowSpec} instance
1185+
*/
1186+
public static WorkflowSpec workflow() {
1187+
return DSL.workflow();
10981188
}
10991189

11001190
// ---------------------------------------------------------------------------

‎experimental/fluent/func/src/main/java/io/serverlessworkflow/fluent/func/spi/FuncDoFluent.java‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import io.serverlessworkflow.fluent.spec.spi.SetFluent;
3535
import io.serverlessworkflow.fluent.spec.spi.SwitchFluent;
3636
import io.serverlessworkflow.fluent.spec.spi.WorkflowFluent;
37+
import java.util.function.Consumer;
3738

3839
public interface FuncDoFluent<SELF extends FuncDoFluent<SELF>>
3940
extends SetFluent<FuncSetTaskBuilder, SELF>,
@@ -45,4 +46,13 @@ public interface FuncDoFluent<SELF extends FuncDoFluent<SELF>>
4546
CallFnFluent<FuncCallTaskBuilder, SELF>,
4647
CallHttpFluent<FuncCallHttpTaskBuilder, SELF>,
4748
CallOpenAPIFluent<FuncCallOpenAPITaskBuilder, SELF>,
48-
WorkflowFluent<WorkflowTaskBuilder, SELF> {}
49+
WorkflowFluent<WorkflowTaskBuilder, SELF> {
50+
51+
default SELF subflow(String name, Consumer<WorkflowTaskBuilder> itemsConfigurer) {
52+
return this.workflow(name, itemsConfigurer);
53+
}
54+
55+
default SELF subflow(Consumer<WorkflowTaskBuilder> itemsConfigurer) {
56+
return this.workflow(itemsConfigurer);
57+
}
58+
}

‎experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java‎

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.http;
2424
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.listen;
2525
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.produced;
26+
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.subflow;
2627
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.switchWhenOrElse;
2728
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.toOne;
28-
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.workflowTask;
29+
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.workflow;
2930
import static io.serverlessworkflow.fluent.spec.dsl.DSL.use;
30-
import static io.serverlessworkflow.fluent.spec.dsl.DSL.workflow;
3131
import static org.junit.jupiter.api.Assertions.assertEquals;
3232
import static org.junit.jupiter.api.Assertions.assertFalse;
3333
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -36,7 +36,6 @@
3636

3737
import io.serverlessworkflow.api.types.CallHTTP;
3838
import io.serverlessworkflow.api.types.Export;
39-
import io.serverlessworkflow.api.types.FlowDirectiveEnum;
4039
import io.serverlessworkflow.api.types.Task;
4140
import io.serverlessworkflow.api.types.TaskItem;
4241
import io.serverlessworkflow.api.types.Workflow;
@@ -178,12 +177,11 @@ void mixed_chaining_order_and_exports() {
178177
}
179178

180179
@Test
181-
void workflow_task_builds_from_func_dsl() {
180+
void subflow_task_builds_from_func_dsl() {
182181
Workflow wf =
183-
FuncWorkflowBuilder.workflow("step-workflow")
182+
FuncWorkflowBuilder.workflow("step-subflow")
184183
.tasks(
185-
workflowTask(
186-
workflow("child.ns", "child-flow", "2.3.4").input("id", 99).await(false)))
184+
subflow(workflow("child.ns", "child-flow", "2.3.4").input("id", 99).await(false)))
187185
.build();
188186

189187
List<TaskItem> items = wf.getDo();
@@ -200,6 +198,28 @@ void workflow_task_builds_from_func_dsl() {
200198
assertFalse(run.isAwait(), "await(false) should be preserved as false");
201199
}
202200

201+
@Test
202+
void subflow_builder_style_builds_correctly() {
203+
Workflow wf =
204+
FuncWorkflowBuilder.workflow("subflow-builder")
205+
.tasks(
206+
subflow(
207+
"my-subflow",
208+
sub ->
209+
sub.namespace("child.ns")
210+
.name("child-flow")
211+
.version("1.0.0")
212+
.input(Map.of("key", "val"))))
213+
.build();
214+
215+
Task t = wf.getDo().get(0).getTask();
216+
assertNotNull(t.getRunTask());
217+
var run = t.getRunTask().getRun().getRunWorkflow();
218+
assertEquals("my-subflow", wf.getDo().get(0).getName());
219+
assertEquals("child-flow", run.getWorkflow().getName());
220+
assertEquals("val", run.getWorkflow().getInput().getAdditionalProperties().get("key"));
221+
}
222+
203223
@Test
204224
void switchWhenOrElse_jq_to_taskName() {
205225
Workflow wf =
@@ -217,13 +237,16 @@ void switchWhenOrElse_jq_to_taskName() {
217237
void switchWhenOrElse_jq_to_directive() {
218238
Workflow wf =
219239
FuncWorkflowBuilder.workflow("jqSwitchDir")
220-
.tasks(switchWhenOrElse(".score >= 80", "pass", FlowDirectiveEnum.END))
240+
.tasks(
241+
switchWhenOrElse(
242+
".score >= 80", "pass", io.serverlessworkflow.api.types.FlowDirectiveEnum.END))
221243
.build();
222244
Task switchTask = wf.getDo().get(0).getTask();
223245
var items = switchTask.getSwitchTask().getSwitch();
224246
assertEquals(".score >= 80", items.get(0).getSwitchCase().getWhen());
225247
assertEquals(
226-
FlowDirectiveEnum.END, items.get(1).getSwitchCase().getThen().getFlowDirectiveEnum());
248+
io.serverlessworkflow.api.types.FlowDirectiveEnum.END,
249+
items.get(1).getSwitchCase().getThen().getFlowDirectiveEnum());
227250
}
228251

229252
@Test
@@ -473,7 +496,9 @@ void function_step_then_task_name_sets_flow_directive() {
473496
void function_step_then_flow_directive_enum_sets_end() {
474497
Workflow wf =
475498
FuncWorkflowBuilder.workflow("intelligent-newsletter")
476-
.tasks(function("myfunction", String::trim, String.class).then(FlowDirectiveEnum.END))
499+
.tasks(
500+
function("myfunction", String::trim, String.class)
501+
.then(io.serverlessworkflow.api.types.FlowDirectiveEnum.END))
477502
.build();
478503

479504
List<TaskItem> items = wf.getDo();
@@ -485,7 +510,7 @@ void function_step_then_flow_directive_enum_sets_end() {
485510
CallJava callJava = (CallJava) t.getCallTask().get();
486511
assertNotNull(callJava.getThen(), "then() should be set on the task");
487512
assertEquals(
488-
FlowDirectiveEnum.END,
513+
io.serverlessworkflow.api.types.FlowDirectiveEnum.END,
489514
callJava.getThen().getFlowDirectiveEnum(),
490515
"then() should be FlowDirectiveEnum.END");
491516
}
@@ -521,7 +546,7 @@ void consume_step_then_flow_directive_enum_sets_end() {
521546
FuncWorkflowBuilder.workflow("intelligent-newsletter")
522547
.tasks(
523548
consume("sendNewsletter", (String s) -> {}, String.class)
524-
.then(FlowDirectiveEnum.END))
549+
.then(io.serverlessworkflow.api.types.FlowDirectiveEnum.END))
525550
.build();
526551

527552
List<TaskItem> items = wf.getDo();
@@ -533,7 +558,7 @@ void consume_step_then_flow_directive_enum_sets_end() {
533558
CallJava callJava = (CallJava) t.getCallTask().get();
534559
assertNotNull(callJava.getThen(), "then() should be set on the consume task");
535560
assertEquals(
536-
FlowDirectiveEnum.END,
561+
io.serverlessworkflow.api.types.FlowDirectiveEnum.END,
537562
callJava.getThen().getFlowDirectiveEnum(),
538563
"then() should be FlowDirectiveEnum.END");
539564
}

0 commit comments

Comments
 (0)