-
Notifications
You must be signed in to change notification settings - Fork 40
/
switch.go
128 lines (108 loc) · 3.28 KB
/
switch.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package builtin
import (
"errors"
"github.com/fission/fission-workflows/pkg/types"
"github.com/fission/fission-workflows/pkg/types/typedvalues"
"github.com/sirupsen/logrus"
)
const (
Switch = "switch"
SwitchInputCondition = "switch" // required
SwitchInputCases = "cases" // optional
SwitchInputDefaultCase = "default" // optional
SwitchCaseKey = "case"
SwitchCaseValue = "action"
)
/*
Switch is very similar to how switch-constructs are implemented in most languages.
In this case the switch is limited to evaluating string keys.
The string-switch is matched to one of the cases, or - if none of those match - the default case.
**Specification**
**input** | required | types | description
----------------|----------|-------------------|--------------------------------------------------------
switch | yes | string | The string to match to one of the cases.
cases | no | list | List of cases to match to.
default | no | * | The default value if there is no matching case.
**output** (*) Either the value of the matching case, the default, or nothing (in case the default is not specified).
**Example**
```yaml
# ...
SwitchExample:
run: switch
inputs:
switch: "{ param() }"
cases:
- case: foo
action: bar
- case: ac
action: me
default: 42
# ...
```
A complete example of this function can be found in the [switchwhale](../examples/whales/switchwhale.wf.yaml) example.
*/
type FunctionSwitch struct{}
func (fn *FunctionSwitch) Invoke(spec *types.TaskInvocationSpec) (*typedvalues.TypedValue, error) {
switchVal, err := fn.getSwitch(spec.Inputs)
if err != nil {
return nil, err
}
cases, defaultCase, err := fn.getCases(spec.Inputs)
if err != nil {
return nil, err
}
// Evaluate
logrus.Infof("Switch looking for %v in %v", switchVal, cases)
if cases != nil {
tv, ok := cases[switchVal]
if ok {
return tv, nil
}
}
return defaultCase, nil
}
func (fn *FunctionSwitch) getSwitch(inputs map[string]*typedvalues.TypedValue) (string, error) {
tv, err := ensureInput(inputs, SwitchInputCondition)
if err != nil {
return "", err
}
return typedvalues.UnwrapString(tv)
}
func (fn *FunctionSwitch) getCases(inputs map[string]*typedvalues.TypedValue) (map[string]*typedvalues.TypedValue,
*typedvalues.TypedValue, error) {
cases := map[string]*typedvalues.TypedValue{}
defaultCase := inputs[SwitchInputDefaultCase]
switchCases, ok := inputs[SwitchInputCases]
if ok {
ir, err := typedvalues.UnwrapArray(switchCases)
if err != nil {
return nil, nil, err
}
for _, c := range ir {
m, ok := c.(map[string]interface{})
if !ok {
return nil, nil, errors.New("invalid case provided")
}
tva, err := typedvalues.Wrap(m[SwitchCaseValue])
if err != nil {
return nil, nil, err
}
ic, ok := m[SwitchCaseKey]
if !ok {
return nil, nil, errors.New("case in switch does not have a key")
}
key, ok := ic.(string)
if !ok {
return nil, nil, errors.New("case key should be a string")
}
cases[key] = tva
}
}
return cases, defaultCase, nil
}
func switchCase(key string, value interface{}) map[string]interface{} {
return map[string]interface{}{
SwitchCaseKey: key,
SwitchCaseValue: value,
}
}