Skip to content

Commit 28e2e7d

Browse files
authored
v08 - fix ContinueAs data field assignment (#92)
Signed-off-by: spolti <filippespolti@gmail.com> Signed-off-by: spolti <filippespolti@gmail.com>
1 parent 10bcfba commit 28e2e7d

13 files changed

+292
-62
lines changed

model/action.go

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -108,58 +108,7 @@ func (f *FunctionRef) UnmarshalJSON(data []byte) error {
108108
return nil
109109
}
110110

111-
return fmt.Errorf("functionRef value '%s' not support, it must be an object or string", string(data))
112-
}
113-
114-
// WorkflowRef holds a reference for a workflow definition
115-
type WorkflowRef struct {
116-
// Sub-workflow unique id
117-
WorkflowID string `json:"workflowId" validate:"required"`
118-
// Sub-workflow version
119-
Version string `json:"version,omitempty"`
120-
121-
// Invoke specifies if the subflow should be invoked sync or async.
122-
// Defaults to sync.
123-
Invoke InvokeKind `json:"invoke,omitempty" validate:"required,oneof=async sync"`
124-
125-
// OnParantComplete specifies how subflow execution should behave when parent workflow completes if invoke is 'async'。
126-
// Defaults to terminate.
127-
OnParentComplete string `json:"onParentComplete,omitempty" validate:"required,oneof=terminate continue"`
128-
}
129-
130-
type workflowRefForUnmarshal WorkflowRef
131-
132-
// UnmarshalJSON implements json.Unmarshaler
133-
func (s *WorkflowRef) UnmarshalJSON(data []byte) error {
134-
data = bytes.TrimSpace(data)
135-
if len(data) == 0 {
136-
return fmt.Errorf("no bytes to unmarshal")
137-
}
138-
139-
var err error
140-
switch data[0] {
141-
case '"':
142-
s.WorkflowID, err = unmarshalString(data)
143-
if err != nil {
144-
return err
145-
}
146-
s.Invoke, s.OnParentComplete = InvokeKindSync, "terminate"
147-
return nil
148-
case '{':
149-
v := workflowRefForUnmarshal{
150-
Invoke: InvokeKindSync,
151-
OnParentComplete: "terminate",
152-
}
153-
err = json.Unmarshal(data, &v)
154-
if err != nil {
155-
// TODO: replace the error message with correct type's name
156-
return err
157-
}
158-
*s = WorkflowRef(v)
159-
return nil
160-
}
161-
162-
return fmt.Errorf("subFlowRef value '%s' not support, it must be an object or string", string(data))
111+
return fmt.Errorf("functionRef value '%s' is not supported, it must be an object or string", string(data))
163112
}
164113

165114
// Sleep defines time periods workflow execution should sleep before & after function execution

model/action_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func TestWorkflowRefUnmarshalJSON(t *testing.T) {
8686
desp: "invalid string or object",
8787
data: `1`,
8888
expect: WorkflowRef{},
89-
err: `subFlowRef value '1' not support, it must be an object or string`,
89+
err: `subFlowRef value '1' is not supported, it must be an object or string`,
9090
},
9191
}
9292
for _, tc := range testCases {

model/auth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func (a *AuthDefinitions) UnmarshalJSON(b []byte) error {
107107
return a.unmarshalMany(b)
108108
}
109109

110-
return fmt.Errorf("auth value '%s' not support, it must be an array or string", string(b))
110+
return fmt.Errorf("auth value '%s' is not supported, it must be an array or string", string(b))
111111
}
112112

113113
func (a *AuthDefinitions) unmarshalFile(data []byte) error {

model/event.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func EventRefStructLevelValidation(structLevel validator.StructLevel) {
5050
if len(eventRef.ResultEventTimeout) > 0 {
5151
err := val.ValidateISO8601TimeDuration(eventRef.ResultEventTimeout)
5252
if err != nil {
53-
structLevel.ReportError(reflect.ValueOf(eventRef.ResultEventTimeout), "ResultEventTimeout", "resultEventTimeout", "reqiso8601duration", "")
53+
structLevel.ReportError(reflect.ValueOf(eventRef.ResultEventTimeout), "ResultEventTimeout", "resultEventTimeout", "iso8601duration", "")
5454
}
5555
}
5656
}

model/event_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func TestEventRefStructLevelValidation(t *testing.T) {
4848
ResultEventTimeout: "10hs",
4949
Invoke: InvokeKindSync,
5050
},
51-
err: `Key: 'EventRef.ResultEventTimeout' Error:Field validation for 'ResultEventTimeout' failed on the 'reqiso8601duration' tag`,
51+
err: `Key: 'EventRef.ResultEventTimeout' Error:Field validation for 'ResultEventTimeout' failed on the 'iso8601duration' tag`,
5252
},
5353
}
5454

model/state_exec_timeout.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type StateExecTimeout struct {
2828
Total string `json:"total" validate:"required,iso8601duration"`
2929
}
3030

31-
// just define another type to unmarshal object, so the UnmarshalJSON will not called recursively
31+
// just define another type to unmarshal object, so the UnmarshalJSON will not be called recursively
3232
type stateExecTimeoutForUnmarshal StateExecTimeout
3333

3434
// UnmarshalJSON unmarshal StateExecTimeout object from json bytes
@@ -57,5 +57,5 @@ func (s *StateExecTimeout) UnmarshalJSON(data []byte) error {
5757
return nil
5858
}
5959

60-
return fmt.Errorf("stateExecTimeout value '%s' not support, it must be an object or string", string(data))
60+
return fmt.Errorf("stateExecTimeout value '%s' is not supported, it must be an object or string", string(data))
6161
}

model/state_exec_timeout_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func TestStateExecTimeoutUnmarshalJSON(t *testing.T) {
7171
data: `PT10S`,
7272

7373
expect: &StateExecTimeout{},
74-
err: `stateExecTimeout value 'PT10S' not support, it must be an object or string`,
74+
err: `stateExecTimeout value 'PT10S' is not supported, it must be an object or string`,
7575
},
7676
{
7777
desp: "invalid total type",

model/states.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ package model
1616

1717
import (
1818
"encoding/json"
19-
2019
"k8s.io/apimachinery/pkg/util/intstr"
2120
)
2221

model/workflow.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ package model
1717
import (
1818
"encoding/json"
1919
"fmt"
20+
"github.com/go-playground/validator/v10"
21+
val "github.com/serverlessworkflow/sdk-go/v2/validator"
22+
"reflect"
2023
)
2124

2225
// InvokeKind defines how the target is invoked.
@@ -58,6 +61,20 @@ var actionsModelMapping = map[string]func(state map[string]interface{}) State{
5861
StateTypeSleep: func(map[string]interface{}) State { return &SleepState{} },
5962
}
6063

64+
func init() {
65+
val.GetValidator().RegisterStructValidation(continueAsStructLevelValidation, ContinueAs{})
66+
}
67+
68+
func continueAsStructLevelValidation(structLevel validator.StructLevel) {
69+
continueAs := structLevel.Current().Interface().(ContinueAs)
70+
if len(continueAs.WorkflowExecTimeout.Duration) > 0 {
71+
if err := val.ValidateISO8601TimeDuration(continueAs.WorkflowExecTimeout.Duration); err != nil {
72+
structLevel.ReportError(reflect.ValueOf(continueAs.WorkflowExecTimeout.Duration),
73+
"workflowExecTimeout", "duration", "iso8601duration", "")
74+
}
75+
}
76+
}
77+
6178
// ActionMode ...
6279
type ActionMode string
6380

@@ -493,16 +510,55 @@ func (e *End) UnmarshalJSON(data []byte) error {
493510
return nil
494511
}
495512

496-
// ContinueAs ...
513+
// ContinueAs can be used to stop the current workflow execution and start another one (of the same or a different type)
497514
type ContinueAs struct {
498515
WorkflowRef
499516
// TODO: add object or string data type
500-
// If string type, an expression which selects parts of the states data output to become the workflow data input of continued execution. If object type, a custom object to become the workflow data input of the continued execution
517+
// If string type, an expression which selects parts of the states data output to become the workflow data input of
518+
// continued execution. If object type, a custom object to become the workflow data input of the continued execution
501519
Data interface{} `json:"data,omitempty"`
502520
// WorkflowExecTimeout Workflow execution timeout to be used by the workflow continuing execution. Overwrites any specific settings set by that workflow
503521
WorkflowExecTimeout WorkflowExecTimeout `json:"workflowExecTimeout,omitempty"`
504522
}
505523

524+
type continueAsForUnmarshal ContinueAs
525+
526+
func (c *ContinueAs) UnmarshalJSON(data []byte) error {
527+
continueAs := make(map[string]json.RawMessage)
528+
if err := json.Unmarshal(data, &continueAs); err != nil {
529+
c.WorkflowID, err = unmarshalString(data)
530+
if err != nil {
531+
return err
532+
}
533+
return nil
534+
}
535+
536+
if err := unmarshalKey("data", continueAs, &c.Data); err != nil {
537+
return err
538+
}
539+
if err := unmarshalKey("workflowExecTimeout", continueAs, &c.WorkflowExecTimeout); err != nil {
540+
return err
541+
}
542+
543+
v := continueAsForUnmarshal{
544+
WorkflowRef: WorkflowRef{
545+
Invoke: "sync",
546+
OnParentComplete: "terminate",
547+
},
548+
Data: c.Data,
549+
WorkflowExecTimeout: c.WorkflowExecTimeout,
550+
}
551+
552+
err := json.Unmarshal(data, &v)
553+
if err != nil {
554+
return fmt.Errorf("continueAs value '%s' is not supported, it must be an object or string", string(data))
555+
}
556+
557+
*c = ContinueAs(v)
558+
return nil
559+
560+
}
561+
506562
// ProduceEvent ...
507563
type ProduceEvent struct {
508564
// References a name of a defined event

model/workflow_ref.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2022 The Serverless Workflow Specification Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package model
16+
17+
import (
18+
"bytes"
19+
"encoding/json"
20+
"fmt"
21+
)
22+
23+
// WorkflowRef holds a reference for a workflow definition
24+
type WorkflowRef struct {
25+
// Sub-workflow unique id
26+
WorkflowID string `json:"workflowId" validate:"required"`
27+
// Sub-workflow version
28+
Version string `json:"version,omitempty"`
29+
30+
// Invoke specifies if the subflow should be invoked sync or async.
31+
// Defaults to sync.
32+
Invoke InvokeKind `json:"invoke,omitempty" validate:"required,oneof=async sync"`
33+
34+
// OnParantComplete specifies how subflow execution should behave when parent workflow completes if invoke is 'async'。
35+
// Defaults to terminate.
36+
OnParentComplete string `json:"onParentComplete,omitempty" validate:"required,oneof=terminate continue"`
37+
}
38+
39+
type workflowRefForUnmarshal WorkflowRef
40+
41+
// UnmarshalJSON implements json.Unmarshaler
42+
func (s *WorkflowRef) UnmarshalJSON(data []byte) error {
43+
data = bytes.TrimSpace(data)
44+
if len(data) == 0 {
45+
return fmt.Errorf("no bytes to unmarshal")
46+
}
47+
48+
var err error
49+
switch data[0] {
50+
case '"':
51+
s.WorkflowID, err = unmarshalString(data)
52+
if err != nil {
53+
return err
54+
}
55+
s.Invoke, s.OnParentComplete = InvokeKindSync, "terminate"
56+
return nil
57+
case '{':
58+
v := workflowRefForUnmarshal{
59+
Invoke: InvokeKindSync,
60+
OnParentComplete: "terminate",
61+
}
62+
err = json.Unmarshal(data, &v)
63+
if err != nil {
64+
// TODO: replace the error message with correct type's name
65+
return err
66+
}
67+
*s = WorkflowRef(v)
68+
return nil
69+
}
70+
71+
return fmt.Errorf("subFlowRef value '%s' is not supported, it must be an object or string", string(data))
72+
}

0 commit comments

Comments
 (0)