diff --git a/spec/examples/applicantrequest.spec.ts b/spec/examples/applicantrequest.spec.ts index 7db8de43..2e71757e 100644 --- a/spec/examples/applicantrequest.spec.ts +++ b/spec/examples/applicantrequest.spec.ts @@ -14,16 +14,16 @@ * limitations under the License. * */ -import {WorkflowBuilder} from "../../src/model/workflow.builder"; import * as fs from "fs"; -import {FunctionDefBuilder} from "../../src/model/function-def.builder"; -import {DatabasedSwitchBuilder} from "../../src/model/databased-switch.builder"; -import {TransitionDataConditionBuilder} from "../../src/model/transition-data-condition.builder"; -import {OperationStateBuilder} from "../../src/model/operation-state.builder"; -import {SubFlowStateBuilder} from "../../src/model/sub-flow-state.builder"; -import {ActionBuilder} from "../../src/model/action.builder"; -import {DefaultTransitionTypeBuilder} from "../../src/model/default-transition-type.builder"; -import {FunctionRefBuilder} from '../../src/model/function-ref.builder'; +import {WorkflowBuilder} from "../../src"; +import {FunctionDefBuilder} from "../../src"; +import {DatabasedSwitchBuilder} from "../../src"; +import {TransitionDataConditionBuilder} from "../../src"; +import {OperationStateBuilder} from "../../src"; +import {SubFlowStateBuilder} from "../../src"; +import {ActionBuilder} from "../../src"; +import {DefaultTransitionBuilder} from "../../src"; +import {FunctionRefBuilder} from "../../src"; describe("applicationrequest workflow example", () => { @@ -53,7 +53,7 @@ describe("applicationrequest workflow example", () => { .withCondition("${ .applicants | .age < 18 }") .withTransition("RejectApplication") .build()]) - .withDefault(new DefaultTransitionTypeBuilder() + .withDefault(new DefaultTransitionBuilder() .withTransition( "RejectApplication", ).build()) diff --git a/spec/examples/booklending.spec.ts b/spec/examples/booklending.spec.ts index 090f8526..5cf1f53b 100644 --- a/spec/examples/booklending.spec.ts +++ b/spec/examples/booklending.spec.ts @@ -14,6 +14,7 @@ * limitations under the License. * */ +import * as fs from 'fs'; import { ActionBuilder, DatabasedSwitchBuilder, @@ -22,15 +23,14 @@ import { TransitionDataConditionBuilder, WorkflowBuilder, } from '../../src'; -import * as fs from 'fs'; -import {StartBuilder} from '../../src/model/start.builder'; -import {EventStateBuilder} from '../../src/model/event-state.builder'; -import {OnEventBuilder} from '../../src/model/on-event.builder'; -import {FunctionRefBuilder} from '../../src/model/function-ref.builder'; -import {FunctionsBuilder} from '../../src/model/functions.builder'; -import {EventBasedSwitchBuilder} from '../../src/model/event-based-switch.builder'; -import {TransitionEventConditionBuilder} from '../../src/model/transition-event-condition.builder'; -import {DelayStateBuilder} from '../../src/model/delay-state.builder'; +import {StartBuilder} from "../../src"; +import {EventStateBuilder} from "../../src"; +import {OnEventBuilder} from "../../src"; +import {FunctionRefBuilder} from "../../src"; +import {FunctionsBuilder} from "../../src"; +import {EventBasedSwitchBuilder} from "../../src"; +import {TransitionEventConditionBuilder} from "../../src"; +import {DelayStateBuilder} from "../../src"; describe("booklending workflow example", () => { @@ -127,11 +127,11 @@ describe("booklending workflow example", () => { ]) .withTransition("Wait two weeks") .build(), - new DelayStateBuilder() - .withName("Wait two weeks") - .withTimeDelay("PT2W") - .withTransition("Get Book Status") - .build(), + new DelayStateBuilder() + .withName("Wait two weeks") + .withTimeDelay("PT2W") + .withTransition("Get Book Status") + .build(), new OperationStateBuilder() .withName("Check Out Book") .withActions([ @@ -140,7 +140,7 @@ describe("booklending workflow example", () => { new FunctionRefBuilder() .withRefName("Check out book with id") .withArguments({ - "bookid": "${ .book.id }" + "bookid": "${ .book.id }", }) .build()) .build(), @@ -150,14 +150,14 @@ describe("booklending workflow example", () => { .withRefName("Notify Lender for checkout") .withArguments({ "bookid": "${ .book.id }", - "lender": "${ .lender }" + "lender": "${ .lender }", }) .build()) - .build() + .build(), ]) .withEnd(true) - .build() + .build(), ]) .withFunctions(new FunctionsBuilder() diff --git a/spec/examples/carauctionbids.json b/spec/examples/carauctionbids.json index 999566b9..e0814d45 100644 --- a/spec/examples/carauctionbids.json +++ b/spec/examples/carauctionbids.json @@ -18,7 +18,8 @@ { "name": "CarBidEvent", "type": "carBidMadeType", - "source": "carBidEventSource" + "source": "carBidEventSource", + "kind": "consumed" } ], "states": [ diff --git a/spec/examples/carauctionbids.spec.ts b/spec/examples/carauctionbids.spec.ts index bfa73072..e0d82730 100644 --- a/spec/examples/carauctionbids.spec.ts +++ b/spec/examples/carauctionbids.spec.ts @@ -16,12 +16,12 @@ */ import {ActionBuilder, FunctionDefBuilder, WorkflowBuilder} from '../../src'; import * as fs from 'fs'; -import {StartBuilder} from '../../src/model/start.builder'; -import {EventsBuilder} from '../../src/model/events.builder'; -import {EventBuilder} from '../../src/model/event.builder'; -import {EventStateBuilder} from '../../src/model/event-state.builder'; -import {OnEventBuilder} from '../../src/model/on-event.builder'; -import {FunctionRefBuilder} from '../../src/model/function-ref.builder'; +import {StartBuilder} from "../../src"; +import {EventsBuilder} from "../../src"; +import {EventBuilder} from "../../src"; +import {EventStateBuilder} from "../../src"; +import {OnEventBuilder} from "../../src"; +import {FunctionRefBuilder} from "../../src"; describe("carauctionbids workflow example", () => { diff --git a/spec/examples/checkcarvitals.json b/spec/examples/checkcarvitals.json new file mode 100644 index 00000000..96ab4078 --- /dev/null +++ b/spec/examples/checkcarvitals.json @@ -0,0 +1,45 @@ +{ + "id": "checkcarvitals", + "name": "Check Car Vitals Workflow", + "version": "1.0", + "start": "WhenCarIsOn", + "states": [ + { + "name": "WhenCarIsOn", + "type": "event", + "onEvents": [ + { + "eventRefs": [ + "CarTurnedOnEvent" + ] + } + ], + "transition": "DoCarVitalsChecks" + }, + { + "name": "DoCarVitalsChecks", + "type": "subflow", + "workflowId": "vitalscheck", + "repeat": { + "stopOnEvents": [ + "CarTurnedOffEvent" + ] + }, + "end": true + } + ], + "events": [ + { + "name": "CarTurnedOnEvent", + "type": "car.events", + "source": "my/car/start", + "kind": "consumed" + }, + { + "name": "CarTurnedOffEvent", + "type": "car.events", + "source": "my/car/start", + "kind": "consumed" + } + ] +} diff --git a/spec/examples/checkcarvitals.spec.ts b/spec/examples/checkcarvitals.spec.ts new file mode 100644 index 00000000..da71d2c0 --- /dev/null +++ b/spec/examples/checkcarvitals.spec.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + EventBuilder, + EventsBuilder, + EventStateBuilder, + OnEventBuilder, + RepeatBuilder, + SubFlowStateBuilder, + WorkflowBuilder, +} from "../../src"; +import * as fs from "fs"; + + +describe("checkcarvitals workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("checkcarvitals") + .withVersion("1.0") + .withName("Check Car Vitals Workflow") + .withStart("WhenCarIsOn") + .withStates([ + new EventStateBuilder() + .withName("WhenCarIsOn") + .withOnEvents([ + new OnEventBuilder() + .withEventsRef(["CarTurnedOnEvent"]) + .build(), + ]) + .withTransition("DoCarVitalsChecks") + .build(), + new SubFlowStateBuilder() + .withName("DoCarVitalsChecks") + .withWorkflowId("vitalscheck") + .withRepeat(new RepeatBuilder() + .withStopOnEvents(["CarTurnedOffEvent"]) + .build()) + .withEnd(true) + .build(), + ]) + .withEvents( + new EventsBuilder() + .withEvents([ + new EventBuilder() + .withName("CarTurnedOnEvent") + .withType("car.events") + .withSource("my/car/start") + .build(), + new EventBuilder() + .withName("CarTurnedOffEvent") + .withType("car.events") + .withSource("my/car/start") + .build(), + + ]).build(), + ) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/checkcarvitals.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/spec/examples/jobmonitoring.json b/spec/examples/jobmonitoring.json new file mode 100644 index 00000000..a313280e --- /dev/null +++ b/spec/examples/jobmonitoring.json @@ -0,0 +1,142 @@ +{ + "id": "jobmonitoring", + "version": "1.0", + "name": "Job Monitoring", + "description": "Monitor finished execution of a submitted job", + "start": "SubmitJob", + "functions": [ + { + "name": "submitJob", + "operation": "http://myapis.org/monitorapi.json#doSubmit", + "type": "rest" + }, + { + "name": "checkJobStatus", + "operation": "http://myapis.org/monitorapi.json#checkStatus", + "type": "rest" + }, + { + "name": "reportJobSuceeded", + "operation": "http://myapis.org/monitorapi.json#reportSucceeded", + "type": "rest" + }, + { + "name": "reportJobFailed", + "operation": "http://myapis.org/monitorapi.json#reportFailure", + "type": "rest" + } + ], + "states": [ + { + "name": "SubmitJob", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "submitJob", + "arguments": { + "name": "${ .job.name }" + } + }, + "actionDataFilter": { + "results": "${ .jobuid }" + } + } + ], + "onErrors": [ + { + "error": "*", + "transition": "SubmitError" + } + ], + "stateDataFilter": { + "output": "${ .jobuid }" + }, + "transition": "WaitForCompletion" + }, + { + "name": "SubmitError", + "type": "subflow", + "workflowId": "handleJobSubmissionErrorWorkflow", + "end": true + }, + { + "name": "WaitForCompletion", + "type": "delay", + "timeDelay": "PT5S", + "transition": "GetJobStatus" + }, + { + "name": "GetJobStatus", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "checkJobStatus", + "arguments": { + "name": "${ .jobuid }" + } + }, + "actionDataFilter": { + "results": "${ .jobstatus }" + } + } + ], + "stateDataFilter": { + "output": "${ .jobstatus }" + }, + "transition": "DetermineCompletion" + }, + { + "name": "DetermineCompletion", + "type": "switch", + "dataConditions": [ + { + "condition": "${ .jobStatus == \"SUCCEEDED\" }", + "transition": "JobSucceeded" + }, + { + "condition": "${ .jobStatus == \"FAILED\" }", + "transition": "JobFailed" + } + ], + "default": { + "transition": "WaitForCompletion" + } + }, + { + "name": "JobSucceeded", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "reportJobSuceeded", + "arguments": { + "name": "${ .jobuid }" + } + } + } + ], + "end": true + }, + { + "name": "JobFailed", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "reportJobFailed", + "arguments": { + "name": "${ .jobuid }" + } + } + } + ], + "end": true + } + ] +} diff --git a/spec/examples/jobmonitoring.spec.ts b/spec/examples/jobmonitoring.spec.ts new file mode 100644 index 00000000..b1cf3569 --- /dev/null +++ b/spec/examples/jobmonitoring.spec.ts @@ -0,0 +1,197 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + ActionBuilder, + ActionDataFilterBuilder, + DatabasedSwitchBuilder, + DefaultTransitionBuilder, + DelayStateBuilder, + FunctionDefBuilder, + FunctionRefBuilder, + OnErrorBuilder, + OperationStateBuilder, + StateDataFilterBuilder, + SubFlowStateBuilder, + TransitionDataConditionBuilder, + WorkflowBuilder, +} from "../../src"; +import * as fs from "fs"; + + +describe("jobmonitoring workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("jobmonitoring") + .withVersion("1.0") + .withName("Job Monitoring") + .withDescription("Monitor finished execution of a submitted job") + .withStart("SubmitJob") + .withFunctions([ + new FunctionDefBuilder() + .withName("submitJob") + .withOperation("http://myapis.org/monitorapi.json#doSubmit") + .build(), + new FunctionDefBuilder() + .withName("checkJobStatus") + .withOperation("http://myapis.org/monitorapi.json#checkStatus") + .build(), + new FunctionDefBuilder() + .withName("reportJobSuceeded") + .withOperation("http://myapis.org/monitorapi.json#reportSucceeded") + .build(), + new FunctionDefBuilder() + .withName("reportJobFailed") + .withOperation("http://myapis.org/monitorapi.json#reportFailure") + .build(), + ]) + .withStates([ + new OperationStateBuilder() + .withName("SubmitJob") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("submitJob") + .withArguments({ + "name": "${ .job.name }", + }) + .build(), + ) + .withActionDataFilter( + new ActionDataFilterBuilder() + .withResults("${ .jobuid }") + .build(), + ) + .build(), + ]) + .withOnErrors([ + new OnErrorBuilder() + .withError("*") + .withTransition("SubmitError") + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .jobuid }") + .build(), + ) + .withTransition("WaitForCompletion") + .build(), + new SubFlowStateBuilder() + .withName("SubmitError") + .withWorkflowId("handleJobSubmissionErrorWorkflow") + .withEnd(true) + .build(), + new DelayStateBuilder() + .withName("WaitForCompletion") + .withTimeDelay("PT5S") + .withTransition("GetJobStatus") + .build(), + new OperationStateBuilder() + .withName("GetJobStatus") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("checkJobStatus") + .withArguments({ + "name": "${ .jobuid }", + }) + .build(), + ) + .withActionDataFilter( + new ActionDataFilterBuilder() + .withResults("${ .jobstatus }") + .build(), + ) + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .jobstatus }") + .build(), + ) + .withTransition("DetermineCompletion") + .build(), + new DatabasedSwitchBuilder() + .withName("DetermineCompletion") + .withDataConditions([ + new TransitionDataConditionBuilder() + .withCondition("${ .jobStatus == \"SUCCEEDED\" }") + .withTransition("JobSucceeded") + .build(), + new TransitionDataConditionBuilder() + .withCondition("${ .jobStatus == \"FAILED\" }") + .withTransition("JobFailed") + .build(), + ]) + .withDefault( + new DefaultTransitionBuilder() + .withTransition("WaitForCompletion") + .build()) + .build(), + new OperationStateBuilder() + .withName("JobSucceeded") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("reportJobSuceeded") + .withArguments({ + "name": "${ .jobuid }", + }) + .build(), + ) + .build(), + ]) + .withEnd(true) + .build(), + new OperationStateBuilder() + .withName("JobFailed") + .withActionMode('sequential') + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("reportJobFailed") + .withArguments({ + "name": "${ .jobuid }", + }) + .build(), + ) + .build(), + ]) + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/jobmonitoring.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/spec/examples/parallel.json b/spec/examples/parallel.json new file mode 100644 index 00000000..a9ffa007 --- /dev/null +++ b/spec/examples/parallel.json @@ -0,0 +1,25 @@ +{ + "id": "parallelexec", + "version": "1.0", + "name": "Parallel Execution Workflow", + "description": "Executes two branches in parallel", + "start": "ParallelExec", + "states":[ + { + "name": "ParallelExec", + "type": "parallel", + "completionType": "and", + "branches": [ + { + "name": "ShortDelayBranch", + "workflowId": "shortdelayworkflowid" + }, + { + "name": "LongDelayBranch", + "workflowId": "longdelayworkflowid" + } + ], + "end": true + } + ] +} diff --git a/spec/examples/parallel.spec.ts b/spec/examples/parallel.spec.ts new file mode 100644 index 00000000..8e68c762 --- /dev/null +++ b/spec/examples/parallel.spec.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as fs from "fs"; +import {BranchBuilder, ParallelStateBuilder, WorkflowBuilder} from '../../src'; + + +describe("parallel workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("parallelexec") + .withVersion("1.0") + .withName("Parallel Execution Workflow") + .withDescription("Executes two branches in parallel") + .withStart("ParallelExec") + .withStates([ + new ParallelStateBuilder() + .withName("ParallelExec") + .withCompletionType("and") + .withBranches([ + new BranchBuilder() + .withName("ShortDelayBranch") + .withWorkflowId("shortdelayworkflowid") + .build(), + new BranchBuilder() + .withName("LongDelayBranch") + .withWorkflowId("longdelayworkflowid") + .build(), + ]) + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/parallel.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/spec/examples/provisionorder.json b/spec/examples/provisionorder.json new file mode 100644 index 00000000..8405975c --- /dev/null +++ b/spec/examples/provisionorder.json @@ -0,0 +1,73 @@ +{ + "id": "provisionorders", + "version": "1.0", + "name": "Provision Orders", + "description": "Provision Orders and handle errors thrown", + "start": "ProvisionOrder", + "functions": [ + { + "name": "provisionOrderFunction", + "operation": "http://myapis.org/provisioningapi.json#doProvision", + "type": "rest" + } + ], + "states": [ + { + "name": "ProvisionOrder", + "type": "operation", + "actionMode": "sequential", + "actions": [ + { + "functionRef": { + "refName": "provisionOrderFunction", + "arguments": { + "order": "${ .order }" + } + } + } + ], + "stateDataFilter": { + "output": "${ .exceptions }" + }, + "transition": "ApplyOrder", + "onErrors": [ + { + "error": "Missing order id", + "transition": "MissingId" + }, + { + "error": "Missing order item", + "transition": "MissingItem" + }, + { + "error": "Missing order quantity", + "transition": "MissingQuantity" + } + ] + }, + { + "name": "MissingId", + "type": "subflow", + "workflowId": "handleMissingIdExceptionWorkflow", + "end": true + }, + { + "name": "MissingItem", + "type": "subflow", + "workflowId": "handleMissingItemExceptionWorkflow", + "end": true + }, + { + "name": "MissingQuantity", + "type": "subflow", + "workflowId": "handleMissingQuantityExceptionWorkflow", + "end": true + }, + { + "name": "ApplyOrder", + "type": "subflow", + "workflowId": "applyOrderWorkflowId", + "end": true + } + ] +} diff --git a/spec/examples/provisionorder.spec.ts b/spec/examples/provisionorder.spec.ts new file mode 100644 index 00000000..3be3c611 --- /dev/null +++ b/spec/examples/provisionorder.spec.ts @@ -0,0 +1,114 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import { + ActionBuilder, + FunctionDefBuilder, + FunctionRefBuilder, + OnErrorBuilder, + OperationStateBuilder, + StateDataFilterBuilder, + SubFlowStateBuilder, + WorkflowBuilder, +} from "../../src"; +import * as fs from "fs"; + + +describe("provisionorder workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("provisionorders") + .withVersion("1.0") + .withName("Provision Orders") + .withDescription("Provision Orders and handle errors thrown") + .withStart("ProvisionOrder") + .withFunctions([ + new FunctionDefBuilder() + .withName("provisionOrderFunction") + .withOperation("http://myapis.org/provisioningapi.json#doProvision") + .build(), + ]) + .withStates([ + new OperationStateBuilder() + .withName("ProvisionOrder") + .withActionMode("sequential") + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("provisionOrderFunction") + .withArguments({ + "order": "${ .order }", + }) + .build(), + ) + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .exceptions }") + .build()) + .withTransition("ApplyOrder") + .withOnErrors([ + new OnErrorBuilder() + .withError("Missing order id") + .withTransition("MissingId") + .build(), + new OnErrorBuilder() + .withError("Missing order item") + .withTransition("MissingItem") + .build(), + new OnErrorBuilder() + .withError("Missing order quantity") + .withTransition("MissingQuantity") + .build(), + ]) + .build(), + new SubFlowStateBuilder() + .withName("MissingId") + .withWorkflowId("handleMissingIdExceptionWorkflow") + .withEnd(true) + .build(), + new SubFlowStateBuilder() + .withName("MissingItem") + .withWorkflowId("handleMissingItemExceptionWorkflow") + .withEnd(true) + .build(), + new SubFlowStateBuilder() + .withName("MissingQuantity") + .withWorkflowId("handleMissingQuantityExceptionWorkflow") + .withEnd(true) + .build(), + new SubFlowStateBuilder() + .withName("ApplyOrder") + .withWorkflowId("applyOrderWorkflowId") + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/provisionorder.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/spec/examples/sendcloudevent.json b/spec/examples/sendcloudevent.json new file mode 100644 index 00000000..b629a292 --- /dev/null +++ b/spec/examples/sendcloudevent.json @@ -0,0 +1,47 @@ +{ + "id": "sendcloudeventonprovision", + "version": "1.0", + "name": "Send CloudEvent on provision completion", + "start": "ProvisionOrdersState", + "events": [ + { + "name": "provisioningCompleteEvent", + "type": "provisionCompleteType", + "kind": "produced" + } + ], + "functions": [ + { + "name": "provisionOrderFunction", + "operation": "http://myapis.org/provisioning.json#doProvision", + "type": "rest" + } + ], + "states": [ + { + "name": "ProvisionOrdersState", + "type": "foreach", + "inputCollection": "${ .orders }", + "iterationParam": "singleorder", + "outputCollection": "${ .provisionedOrders }", + "actions": [ + { + "functionRef": { + "refName": "provisionOrderFunction", + "arguments": { + "order": "${ .singleorder }" + } + } + } + ], + "end": { + "produceEvents": [ + { + "eventRef": "provisioningCompleteEvent", + "data": "${ .provisionedOrders }" + } + ] + } + } + ] +} diff --git a/spec/examples/sendcloudevent.spec.ts b/spec/examples/sendcloudevent.spec.ts new file mode 100644 index 00000000..9b5b14ad --- /dev/null +++ b/spec/examples/sendcloudevent.spec.ts @@ -0,0 +1,99 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {WorkflowBuilder} from "../../src"; +import * as fs from "fs"; +import { + ActionBuilder, EndBuilder, + EventBuilder, + EventsBuilder, + ForEachStateBuilder, + FunctionDefBuilder, + FunctionRefBuilder, + ProduceEventDefBuilder, +} from '../../src'; + + +describe("sendcloudevent workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("sendcloudeventonprovision") + .withVersion("1.0") + .withName("Send CloudEvent on provision completion") + .withStart("ProvisionOrdersState") + .withEvents( + new EventsBuilder() + .withEvents([ + new EventBuilder() + .withName("provisioningCompleteEvent") + .withType("provisionCompleteType") + .withKind("produced") + .build(), + + ]).build(), + ) + .withFunctions([ + new FunctionDefBuilder() + .withName("provisionOrderFunction") + .withOperation("http://myapis.org/provisioning.json#doProvision") + .build(), + ]) + .withStates([ + new ForEachStateBuilder() + .withName("ProvisionOrdersState") + .withInputCollection("${ .orders }") + .withIterationParam("singleorder") + .withOutputCollection("${ .provisionedOrders }") + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("provisionOrderFunction") + .withArguments({ + "order": "${ .singleorder }", + }) + .build(), + ) + .build(), + ]) + .withEnd( + new EndBuilder() + .withProduceEvents([ + new ProduceEventDefBuilder() + .withEventRef("provisioningCompleteEvent") + .withData("${ .provisionedOrders }") + .build(), + ]) + .build(), + ) + .build(), + ]) + .build(); + + + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/sendcloudevent.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/spec/examples/solvemathproblems.json b/spec/examples/solvemathproblems.json new file mode 100644 index 00000000..7b39d1c8 --- /dev/null +++ b/spec/examples/solvemathproblems.json @@ -0,0 +1,37 @@ +{ + "id": "solvemathproblems", + "version": "1.0", + "name": "Solve Math Problems Workflow", + "description": "Solve math problems", + "start": "Solve", + "functions": [ + { + "name": "solveMathExpressionFunction", + "type": "rest", + "operation": "http://myapis.org/mapthapis.json#solveExpression" + } + ], + "states": [ + { + "name": "Solve", + "type": "foreach", + "inputCollection": "${ .expressions }", + "iterationParam": "singleexpression", + "outputCollection": "${ .results }", + "actions": [ + { + "functionRef": { + "refName": "solveMathExpressionFunction", + "arguments": { + "expression": "${ .singleexpression }" + } + } + } + ], + "stateDataFilter": { + "output": "${ .results }" + }, + "end": true + } + ] +} diff --git a/spec/examples/solvemathproblems.spec.ts b/spec/examples/solvemathproblems.spec.ts new file mode 100644 index 00000000..3bf2c2a5 --- /dev/null +++ b/spec/examples/solvemathproblems.spec.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {WorkflowBuilder} from "../../src/model/workflow.builder"; +import * as fs from "fs"; +import {ActionBuilder, FunctionDefBuilder, FunctionRefBuilder} from '../../src'; +import {ForEachStateBuilder} from '../../src/model/for-each-state.builder'; +import {StateDataFilterBuilder} from '../../src/model/state-data-filter.builder'; + + +describe("solvemathproblems workflow example", () => { + + + it('should generate Workflow object', function () { + + const workflow = new WorkflowBuilder() + .withId("solvemathproblems") + .withVersion("1.0") + .withName("Solve Math Problems Workflow") + .withDescription("Solve math problems") + .withStart("Solve") + .withFunctions([ + new FunctionDefBuilder() + .withName("solveMathExpressionFunction") + .withOperation("http://myapis.org/mapthapis.json#solveExpression") + .build(), + ]) + .withStates([ + new ForEachStateBuilder() + .withName("Solve") + .withInputCollection("${ .expressions }") + .withIterationParam("singleexpression") + .withOutputCollection("${ .results }") + .withActions([ + new ActionBuilder() + .withFunctionRef( + new FunctionRefBuilder() + .withRefName("solveMathExpressionFunction") + .withArguments({ + "expression": "${ .singleexpression }", + }) + .build()) + .build(), + ]) + .withStateDataFilter( + new StateDataFilterBuilder() + .withOutput("${ .results }") + .build(), + ) + .withEnd(true) + .build(), + ]) + .build(); + + + const expected = JSON.parse(fs.readFileSync("./spec/examples/solvemathproblems.json") + .toLocaleString()) as any; + expect(workflow).toEqual(expected); + + }); + + +}); diff --git a/spec/model/action-builder.spec.ts b/spec/model/action-builder.spec.ts index 61d8887c..a08622d7 100644 --- a/spec/model/action-builder.spec.ts +++ b/spec/model/action-builder.spec.ts @@ -15,7 +15,7 @@ * */ -import {ActionBuilder, ActionDataFilterType, EventRef} from '../../src'; +import {ActionBuilder, ActionDataFilter, EventRef} from '../../src'; import {ActionDataFilterBuilder} from '../../src/model/action-data-filter.builder'; @@ -63,7 +63,7 @@ describe("ActionBuilder", () => { }); -function validActionDataFilter(): ActionDataFilterType { +function validActionDataFilter(): ActionDataFilter { return {}; } diff --git a/src/index.ts b/src/index.ts index 3822ed16..5223b3d2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,26 +19,32 @@ export {BaseWorkflow} from "./base-workflow"; export {ActionBuilder} from "./model/action.builder"; export {ActionDataFilterBuilder} from "./model/action-data-filter.builder"; +export {BranchBuilder} from "./model/branch.builder"; export {CronDefBuilder} from "./model/cron-def.builder"; export {DelayStateBuilder} from "./model/delay-state.builder"; export {DatabasedSwitchBuilder} from "./model/databased-switch.builder"; -export {DefaultTransitionTypeBuilder} from "./model/default-transition-type.builder"; +export {DefaultTransitionBuilder} from "./model/default-transition.builder"; +export {EndBuilder} from "./model/end.builder"; export {EventBuilder} from "./model/event.builder"; export {EventBasedSwitchBuilder} from "./model/event-based-switch.builder"; export {EventRefBuilder} from "./model/event-ref.builder"; export {EventStateBuilder} from "./model/event-state.builder"; export {EventsBuilder} from "./model/events.builder"; +export {ForEachStateBuilder} from "./model/for-each-state.builder"; export {FunctionDefBuilder} from "./model/function-def.builder"; export {FunctionRefBuilder} from "./model/function-ref.builder"; export {FunctionsBuilder} from "./model/functions.builder"; export {InjectStateBuilder} from "./model/inject-state.builder"; export {MetadataBuilder} from "./model/metadata.builder"; export {OnEventBuilder} from "./model/on-event.builder"; +export {OnErrorBuilder} from "./model/on-error.builder"; export {OperationStateBuilder} from "./model/operation-state.builder"; +export {ParallelStateBuilder} from './model/parallel-state.builder'; export {ProduceEventDefBuilder} from "./model/produce-event-def.builder"; export {RepeatBuilder} from "./model/repeat.builder"; export {ScheduleBuilder} from "./model/schedule.builder"; export {StartBuilder} from "./model/start.builder"; +export {StateDataFilterBuilder} from "./model/state-data-filter.builder"; export {SubFlowStateBuilder} from "./model/sub-flow-state.builder"; export {TransitionDataConditionBuilder} from "./model/transition-data-condition.builder"; export {TransitionEventConditionBuilder} from "./model/transition-event-condition.builder"; diff --git a/src/model/action-data-filter.builder.ts b/src/model/action-data-filter.builder.ts index e151e581..d95a01f4 100644 --- a/src/model/action-data-filter.builder.ts +++ b/src/model/action-data-filter.builder.ts @@ -14,10 +14,10 @@ * limitations under the License. * */ -import {ActionDataFilterType} from '../index'; +import {ActionDataFilter} from '../index'; export class ActionDataFilterBuilder { - private readonly model: ActionDataFilterType = {}; + private readonly model: ActionDataFilter = {}; withFromStateData(value: string): ActionDataFilterBuilder { @@ -35,7 +35,7 @@ export class ActionDataFilterBuilder { return this; } - build(): ActionDataFilterType { + build(): ActionDataFilter { return this.model; } diff --git a/src/model/action.builder.ts b/src/model/action.builder.ts index c4e1a464..f0fddc9f 100644 --- a/src/model/action.builder.ts +++ b/src/model/action.builder.ts @@ -14,7 +14,7 @@ * limitations under the License. * */ -import {ActionDataFilterType, Action, EventRef, FunctionRef} from "./types"; +import {ActionDataFilter, Action, EventRef, FunctionRef} from "./types"; export class ActionBuilder { @@ -42,7 +42,7 @@ export class ActionBuilder { } - withActionDataFilter(value: ActionDataFilterType): ActionBuilder { + withActionDataFilter(value: ActionDataFilter): ActionBuilder { this.model.actionDataFilter = value; return this; diff --git a/src/model/branch.builder.ts b/src/model/branch.builder.ts new file mode 100644 index 00000000..5db7d102 --- /dev/null +++ b/src/model/branch.builder.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {Branch} from './types'; + +export class BranchBuilder { + // @ts-ignore + private model: Branch = {}; + + withName(value: string): BranchBuilder { + this.model.name = value; + return this; + + } + + withWorkflowId(value: string): BranchBuilder { + this.model.workflowId = value; + return this; + + } + + build(): Branch { + return this.model; + + } +} diff --git a/src/model/databased-switch.builder.ts b/src/model/databased-switch.builder.ts index 1828516f..ff9095d7 100644 --- a/src/model/databased-switch.builder.ts +++ b/src/model/databased-switch.builder.ts @@ -15,7 +15,7 @@ * */ import {DataDasedSwitch} from "./workflow"; -import {DataConditions, DefaultTransitionType} from "./types"; +import {DataConditions, DefaultTransition} from "./types"; export class DatabasedSwitchBuilder { @@ -38,7 +38,7 @@ export class DatabasedSwitchBuilder { } - withDefault(value: DefaultTransitionType): DatabasedSwitchBuilder { + withDefault(value: DefaultTransition): DatabasedSwitchBuilder { this.model.default = value; return this; } diff --git a/src/model/default-transition-type.builder.ts b/src/model/default-transition.builder.ts similarity index 77% rename from src/model/default-transition-type.builder.ts rename to src/model/default-transition.builder.ts index b27fa9aa..8855c597 100644 --- a/src/model/default-transition-type.builder.ts +++ b/src/model/default-transition.builder.ts @@ -14,20 +14,20 @@ * limitations under the License. * */ -import {DefaultTransitionType} from "./types"; +import {DefaultTransition} from "./types"; import {Transition} from "./workflow"; -export class DefaultTransitionTypeBuilder { +export class DefaultTransitionBuilder { // @ts-ignore - private model: DefaultTransitionType = {}; + private model: DefaultTransition = {}; - withTransition(value: Transition): DefaultTransitionTypeBuilder { + withTransition(value: Transition): DefaultTransitionBuilder { this.model.transition = value; return this; } - build(): DefaultTransitionType { + build(): DefaultTransition { //TODO validate either transition or end return this.model; } diff --git a/src/model/end.builder.ts b/src/model/end.builder.ts new file mode 100644 index 00000000..92fc9537 --- /dev/null +++ b/src/model/end.builder.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {End, ProduceEventsDef, Terminate} from './types'; + +export class EndBuilder { + private terminate: Terminate = false; + private produceEvents: ProduceEventsDef; + private compensate: boolean; + + withProduceEvents(value: ProduceEventsDef): EndBuilder { + this.produceEvents = value; + return this; + } + + withCompensate(value: boolean): EndBuilder { + this.compensate = value; + return this; + } + + build(): End { + + let isObject: boolean = false; + const result: End = {}; + + + if (this.produceEvents) { + result.produceEvents = this.produceEvents; + isObject = true; + } + if (this.compensate) { + result.compensate = this.compensate; + isObject = true; + } + if (isObject) { + return result; + } + + return this.terminate; + } + +} diff --git a/src/model/event.builder.ts b/src/model/event.builder.ts index e7b18b6d..70453c2d 100644 --- a/src/model/event.builder.ts +++ b/src/model/event.builder.ts @@ -14,10 +14,12 @@ * limitations under the License. * */ -import {EventDef, EventName} from './types'; +import {EventDef, EventKind, EventName} from './types'; export class EventBuilder { - private model: EventDef = {}; + private model: EventDef = { + kind: "consumed" + }; withName(value: EventName): EventBuilder { this.model.name = value; @@ -35,9 +37,15 @@ export class EventBuilder { } + withKind(value: EventKind): any { + this.model.kind = value; + return this; + } + build(): EventDef { //TODO validate return this.model; } + } diff --git a/src/model/for-each-state.builder.ts b/src/model/for-each-state.builder.ts new file mode 100644 index 00000000..fb17972c --- /dev/null +++ b/src/model/for-each-state.builder.ts @@ -0,0 +1,65 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {Actions, End, ForEachState, StateDataFilter} from '../index'; + +export class ForEachStateBuilder { + + private model: ForEachState = { + type: "foreach", + }; + + withName(value: string): ForEachStateBuilder { + this.model.name = value; + return this; + } + + withInputCollection(value: string): ForEachStateBuilder { + this.model.inputCollection = value; + return this; + } + + withIterationParam(value: string): ForEachStateBuilder { + this.model.iterationParam = value; + return this; + } + + withOutputCollection(value: string): ForEachStateBuilder { + this.model.outputCollection = value; + return this; + } + + withActions(value: Actions) { + this.model.actions = value; + return this; + + } + + withStateDataFilter(value: StateDataFilter): ForEachStateBuilder { + this.model.stateDataFilter = value; + return this; + } + + withEnd(value: End): any { + this.model.end = value; + return this; + } + + build(): ForEachState { + return this.model; + } + +} diff --git a/src/model/inject-state.builder.ts b/src/model/inject-state.builder.ts index a0791cdb..0f5837cb 100644 --- a/src/model/inject-state.builder.ts +++ b/src/model/inject-state.builder.ts @@ -15,6 +15,7 @@ * */ import {InjectState} from "./workflow"; +import {End} from './types'; export class InjectStateBuilder { private model: InjectState = { @@ -35,7 +36,7 @@ export class InjectStateBuilder { } - withEnd(value: boolean) { + withEnd(value: End): InjectStateBuilder { this.model.end = value; return this; diff --git a/src/model/on-error.builder.ts b/src/model/on-error.builder.ts new file mode 100644 index 00000000..51de1c9d --- /dev/null +++ b/src/model/on-error.builder.ts @@ -0,0 +1,21 @@ +import {OnError, Transition} from '../index'; + +export class OnErrorBuilder { + // @ts-ignore + private model: OnError = {}; + + withError(value: string): OnErrorBuilder { + this.model.error = value; + return this; + } + + withTransition(value: Transition): OnErrorBuilder { + this.model.transition = value; + return this; + } + + build(): OnError { + return this.model; + } + +} diff --git a/src/model/operation-state.builder.ts b/src/model/operation-state.builder.ts index bc5d8462..9c9ef581 100644 --- a/src/model/operation-state.builder.ts +++ b/src/model/operation-state.builder.ts @@ -14,45 +14,56 @@ * limitations under the License. * */ -import {OperationState, Transition} from "./workflow"; -import {ActionModeType, Actions} from "./types"; +import {OnErrors, OperationState, Transition} from "./workflow"; +import {ActionModeType, Actions, End, StateDataFilter} from "./types"; export class OperationStateBuilder { - - private model: OperationState = { - type: "operation" - } - - withName(value: string): OperationStateBuilder { - this.model.name = value; - return this; - - } - - - withActionMode(value: ActionModeType): OperationStateBuilder { - this.model.actionMode = value; - return this; - - } - - withEnd(value: boolean): OperationStateBuilder { - this.model.end = value; - return this; - } - - withActions(value: Actions): OperationStateBuilder { - this.model.actions = value; - return this; - } - - withTransition(value: Transition): OperationStateBuilder { - this.model.transition = value; - return this; - - } - build(): OperationState { - return this.model; - } - + + private model: OperationState = { + type: "operation", + }; + + withName(value: string): OperationStateBuilder { + this.model.name = value; + return this; + + } + + + withActionMode(value: ActionModeType): OperationStateBuilder { + this.model.actionMode = value; + return this; + + } + + withEnd(value: End): OperationStateBuilder { + this.model.end = value; + return this; + } + + withActions(value: Actions): OperationStateBuilder { + this.model.actions = value; + return this; + } + + withTransition(value: Transition): OperationStateBuilder { + this.model.transition = value; + return this; + + } + + withStateDataFilter(value: StateDataFilter): OperationStateBuilder { + this.model.stateDataFilter = value; + return this; + } + + withOnErrors(value: OnErrors): OperationStateBuilder { + this.model.onErrors = value; + return this; + } + + build(): OperationState { + return this.model; + } + } diff --git a/src/model/parallel-state.builder.ts b/src/model/parallel-state.builder.ts new file mode 100644 index 00000000..e61ab382 --- /dev/null +++ b/src/model/parallel-state.builder.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {ParallelState} from './workflow'; +import {Branches, CompletionType, End} from './types'; + +export class ParallelStateBuilder { + private model: ParallelState = { + type: "parallel", + }; + + + withName(value: string): ParallelStateBuilder { + this.model.name = value; + return this; + + } + + withCompletionType(value: CompletionType): ParallelStateBuilder { + this.model.completionType = value; + return this; + + } + + withBranches(value: Branches): ParallelStateBuilder { + this.model.branches = value; + return this; + } + + withEnd(value: End): ParallelStateBuilder { + this.model.end = value; + return this; + + } + + build(): ParallelState { + return this.model; + } + + +} diff --git a/src/model/produce-event-def.builder.ts b/src/model/produce-event-def.builder.ts index 4d97d6ca..59008d50 100644 --- a/src/model/produce-event-def.builder.ts +++ b/src/model/produce-event-def.builder.ts @@ -32,7 +32,7 @@ export class ProduceEventDefBuilder { } - withContextAttributes(value: object): any { + withContextAttributes(value: object): ProduceEventDefBuilder { this.model.contextAttributes = value; return this; } diff --git a/src/model/repeat.builder.ts b/src/model/repeat.builder.ts index b301c7e9..8c4239d7 100644 --- a/src/model/repeat.builder.ts +++ b/src/model/repeat.builder.ts @@ -14,10 +14,10 @@ * limitations under the License. * */ -import {EventsName, RepeatType} from './types'; +import {EventsName, Repeat} from './types'; export class RepeatBuilder { - private model: RepeatType = {}; + private model: Repeat = {}; withExpression(value: string): RepeatBuilder { @@ -47,7 +47,7 @@ export class RepeatBuilder { return this; } - build(): RepeatType { + build(): Repeat { return this.model; } diff --git a/src/model/state-data-filter.builder.ts b/src/model/state-data-filter.builder.ts new file mode 100644 index 00000000..5a1b9145 --- /dev/null +++ b/src/model/state-data-filter.builder.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2021-Present The Serverless Workflow Specification Authors + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import {StateDataFilter} from '../index'; + +export class StateDataFilterBuilder { + private model: StateDataFilter = {}; + + withOutput(value: string): StateDataFilterBuilder { + this.model.output = value; + return this; + } + + build(): StateDataFilter { + return this.model; + + } +} diff --git a/src/model/sub-flow-state.builder.ts b/src/model/sub-flow-state.builder.ts index 714d2699..398193af 100644 --- a/src/model/sub-flow-state.builder.ts +++ b/src/model/sub-flow-state.builder.ts @@ -15,6 +15,7 @@ * */ import {SubFlowState} from "./workflow"; +import {End, Repeat} from './types'; export class SubFlowStateBuilder { private model: SubFlowState = { @@ -32,14 +33,19 @@ export class SubFlowStateBuilder { return this; } - withEnd(value: boolean): SubFlowStateBuilder { + withEnd(value: End): SubFlowStateBuilder { this.model.end = value; return this; } + withRepeat(value: Repeat): SubFlowStateBuilder { + this.model.repeat = value; + return this; + } + build(): SubFlowState { return this.model; } - + } diff --git a/src/model/types.ts b/src/model/types.ts index 9986a4ae..9345d0dc 100644 --- a/src/model/types.ts +++ b/src/model/types.ts @@ -17,7 +17,6 @@ import { CallbackState, DelayState, - End, EndDataCondition, ForEachState, InjectState, OnErrors, @@ -63,7 +62,7 @@ export type EventRef = { contextAttributes?: ContextAttributes; }; -export type ActionDataFilterType = { +export type ActionDataFilter = { /** * Workflow expression that selects state data that the state action can use */ @@ -98,7 +97,7 @@ export type Action = { /** * Action data filter */ - actionDataFilter?: ActionDataFilterType; + actionDataFilter?: ActionDataFilter; }; export type Actions = Action[]; @@ -162,12 +161,13 @@ export type StateDataFilter = { output?: string; }; -export type EndType = | boolean +export type Terminate = boolean; +export type End = | Terminate | { /** * If true, completes all execution flows in the given workflow instance */ - terminate?: boolean; + terminate?: Terminate; /** * Defines events that should be produced */ @@ -181,7 +181,7 @@ export type EndType = | boolean export type DataConditions = (TransitionDataCondition | EndDataCondition)[]; export type ActionModeType = "sequential" | "parallel"; -export type DefaultTransitionType = { +export type DefaultTransition = { transition: Transition; end: End; }; @@ -202,6 +202,7 @@ export type Metadata = { [k: string]: string; }; +export type EventKind = "consumed" | "produced"; export type EventDef = { /** * Unique event name @@ -218,7 +219,7 @@ export type EventDef = { /** * Defines the CloudEvent as either 'consumed' or 'produced' by the workflow. Default is 'consumed' */ - kind?: "consumed" | "produced"; + kind?: EventKind; /** * CloudEvent correlation definitions */ @@ -297,7 +298,7 @@ export type EventName = string; export type EventsName = [EventName, ...EventName[]]; -export type RepeatType = { +export type Repeat = { /** * Expression evaluated against SubFlow state data. SubFlow will repeat execution as long as this expression is true or until the max property count is reached */ @@ -465,3 +466,37 @@ export interface TransitionDataCondition { */ metadata?: Metadata; } + + + +export type Branch = + { + /** + * Branch name + */ + name: string; + /** + * Actions to be executed in this branch + */ + actions?: Action[]; + /** + * Unique Id of a workflow to be executed in this branch + */ + workflowId: string; + } | { + /** + * Branch name + */ + name: string; + /** + * Actions to be executed in this branch + */ + actions: Action[]; + /** + * Unique Id of a workflow to be executed in this branch + */ + workflowId?: string; +}; +export type Branches = Branch[]; + +export type CompletionType = "and" | "xor" | "n_of_m"; diff --git a/src/model/workflow.ts b/src/model/workflow.ts index f199ccdd..1b1b7bcb 100644 --- a/src/model/workflow.ts +++ b/src/model/workflow.ts @@ -16,17 +16,18 @@ */ import { ActionModeType, - Actions, + Actions, Branches, CompletionType, CronDef, DataConditions, - DefaultTransitionType, - EndType, EventName, + DefaultTransition, + End, + EventName, Events, Functions, Interval, Metadata, ProduceEventsDef, - RepeatType, + Repeat, RetriesDef, StartScheduled, StateDataFilter, @@ -134,22 +135,6 @@ export type Transition = */ compensate?: boolean; }; -export type End = - | boolean - | { - /** - * If true, completes all execution flows in the given workflow instance - */ - terminate?: boolean; - /** - * Defines events that should be produced - */ - produceEvents?: ProduceEventsDef; - /** - * If set to true, triggers workflow compensation. Default is false - */ - compensate?: boolean; -}; export interface Exectimeout { /** @@ -185,7 +170,7 @@ export interface DelayState { /** * State end definition */ - end?: EndType; + end?: End; /** * State data filter */ @@ -237,7 +222,7 @@ export interface OperationState { * State end definition */ end?: - EndType; + End; /** * State data filter */ @@ -272,6 +257,7 @@ export interface OperationState { metadata?: Metadata; } + /** * Consists of a number of states that are executed in parallel */ @@ -292,7 +278,7 @@ export interface ParallelState { * State end definition */ end?: - EndType; + End; /** * State data filter */ @@ -300,18 +286,11 @@ export interface ParallelState { /** * Branch Definitions */ - branches?: ( - | { - [k: string]: unknown; - } - | { - [k: string]: unknown; - } - )[]; + branches?: Branches; /** * Option model on how to complete branch execution. */ - completionType?: "and" | "xor" | "n_of_m"; + completionType?: CompletionType; /** * Used when completionType is set to 'n_of_m' to specify the 'N' value */ @@ -370,7 +349,7 @@ export interface DataDasedSwitch { /** * Default transition of the workflow if there is no matching data conditions. Can include a transition or end definition */ - default?: DefaultTransitionType; + default?: DefaultTransition; /** * Unique Name of a workflow state which is responsible for compensation of this state */ @@ -386,7 +365,6 @@ export interface DataDasedSwitch { } - /** * Switch state data based condition */ @@ -402,7 +380,7 @@ export interface EndDataCondition { /** * Workflow end definition */ - end: EndType; + end: End; /** * Metadata information */ @@ -470,7 +448,7 @@ export interface EventBasedSwitch { /** * Default transition of the workflow if there is no matching data conditions. Can include a transition or end definition */ - default?: DefaultTransitionType; + default?: DefaultTransition; /** * Unique Name of a workflow state which is responsible for compensation of this state */ @@ -536,7 +514,7 @@ export interface EnddEventCondition { * Explicit transition to end */ end: - EndType; + End; /** * Event data filter definition */ @@ -577,7 +555,7 @@ export interface SubFlowState { * State end definition */ end?: - EndType; + End; /** * Workflow execution must wait for sub-workflow to finish before continuing */ @@ -589,7 +567,7 @@ export interface SubFlowState { /** * SubFlow state repeat exec definition */ - repeat?: RepeatType; + repeat?: Repeat; /** * State data filter */ @@ -636,7 +614,7 @@ export interface InjectState { * State end definition */ end?: - EndType; + End; /** * JSON object which can be set as states data input and can be manipulated via filters */ @@ -685,7 +663,7 @@ export interface ForEachState { * State end definition */ end?: - EndType; + End; /** * Workflow expression selecting an array element of the states data */ @@ -705,14 +683,7 @@ export interface ForEachState { /** * Actions to be executed for each of the elements of inputCollection */ - actions?: ( - | { - [k: string]: unknown; - } - | { - [k: string]: unknown; - } - )[]; + actions?: Actions; /** * Unique Id of a workflow to be executed for each of the elements of inputCollection */ @@ -806,7 +777,7 @@ export interface CallbackState { * State end definition */ end?: - EndType; + End; /** * Unique Name of a workflow state which is responsible for compensation of this state */