-
Notifications
You must be signed in to change notification settings - Fork 8
/
encoders.go
139 lines (118 loc) · 3.38 KB
/
encoders.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
129
130
131
132
133
134
135
136
137
138
139
package runner
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/b2wdigital/restQL-golang/v4/internal/domain"
"github.com/b2wdigital/restQL-golang/v4/pkg/restql"
)
// ApplyEncoders transform parameter values with encoder functions applied
// into a Resource collection with the values processed.
func ApplyEncoders(resources domain.Resources, log restql.Logger) domain.Resources {
for resourceID, statement := range resources {
if statement, ok := statement.(domain.Statement); ok {
resources[resourceID] = applyEncoderToStatement(log, statement)
}
}
return resources
}
func applyEncoderToStatement(log restql.Logger, statement domain.Statement) domain.Statement {
values := statement.With.Values
for key, value := range values {
result := applyEncoderToValue(log, value)
values[key] = result
}
body := applyEncoderToBody(log, statement.With.Body)
statement.With.Body = body
statement.With.Values = values
return statement
}
func applyEncoderToBody(log restql.Logger, body interface{}) interface{} {
switch body := body.(type) {
case domain.Base64:
return applyBase64encoder(applyEncoderToBody(log, body.Target()))
case domain.JSON:
return applyEncoderToBody(log, body.Target())
case domain.Flatten:
return applyFlattenEncoder(log, applyEncoderToBody(log, body.Target()))
case domain.Function:
return body.Map(func(target interface{}) interface{} {
return applyEncoderToBody(log, target)
})
default:
return body
}
}
func applyEncoderToValue(log restql.Logger, value interface{}) interface{} {
switch value := value.(type) {
case domain.Base64:
target := value.Target()
if _, ok := target.(domain.Chain); ok {
return value
}
return applyBase64encoder(applyEncoderToValue(log, value.Target()))
case domain.JSON:
target := value.Target()
if _, ok := target.(domain.Chain); ok {
return value
}
return applyJSONEncoder(log, applyEncoderToValue(log, value.Target()))
case domain.Flatten:
target := value.Target()
if _, ok := target.(domain.Chain); ok {
return value
}
return applyFlattenEncoder(log, applyEncoderToValue(log, value.Target()))
case domain.Function:
return value.Map(func(target interface{}) interface{} {
return applyEncoderToValue(log, target)
})
case map[string]interface{}:
m := make(map[string]interface{})
for k, v := range value {
m[k] = applyEncoderToValue(log, v)
}
return m
case []interface{}:
l := make([]interface{}, len(value))
for i, v := range value {
l[i] = applyEncoderToValue(log, v)
}
return l
default:
return value
}
}
func applyJSONEncoder(log restql.Logger, value interface{}) interface{} {
data, err := json.Marshal(value)
if err != nil {
log.Debug("failed to apply json encoder", "target", value)
}
return string(data)
}
func applyBase64encoder(value interface{}) interface{} {
data := []byte(fmt.Sprintf("%v", value))
return base64.StdEncoding.EncodeToString(data)
}
func applyFlattenEncoder(log restql.Logger, value interface{}) interface{} {
if value, ok := value.([]interface{}); ok {
return flatten(value)
}
log.Warn("flatten encoder used on non list value", "value", value)
return value
}
func flatten(ii []interface{}) []interface{} {
var res []interface{}
for _, i := range ii {
if i == nil {
continue
}
switch t := i.(type) {
case []interface{}:
res = append(res, flatten(t)...)
default:
res = append(res, i)
}
}
return res
}