Skip to content

Commit f602950

Browse files
committed
Add type safe Value definition for OTTL
Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
1 parent 8ecc777 commit f602950

22 files changed

Lines changed: 1722 additions & 0 deletions

.cursor/worktrees.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"setup-worktree": [
3+
"npm install"
4+
]
5+
}

pkg/ottl/ottlruntime/bool.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ottlruntime // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlruntime"
5+
6+
import (
7+
"fmt"
8+
"strconv"
9+
10+
"go.opentelemetry.io/collector/pdata/pcommon"
11+
)
12+
13+
type BoolValue interface {
14+
Value
15+
16+
// Val returns the underlying value, if IsNil is true this panics.
17+
Val() bool
18+
}
19+
20+
func NewBoolValue(val bool) BoolValue {
21+
return newValue(val, false)
22+
}
23+
24+
func NewNilBoolValue() BoolValue {
25+
return newValue(false, true)
26+
}
27+
28+
func ToBoolValue(v Value) (BoolValue, error) {
29+
if val, ok := v.(BoolValue); ok {
30+
return val, nil
31+
}
32+
if v.IsNil() {
33+
return nil, fmt.Errorf("unsupported type conversion from nil %T to \"BoolValue\"", v)
34+
}
35+
switch val := v.(type) {
36+
case StringValue:
37+
return boolTransformFromString(val)
38+
case Int64Value:
39+
return boolTransformFromInt64(val)
40+
case Float64Value:
41+
return boolTransformFromFloat64(val)
42+
case PValueValue:
43+
return boolTransformFromPValue(val)
44+
default:
45+
return nil, fmt.Errorf("unsupported type conversion from %T to \"bool\"", v)
46+
}
47+
}
48+
49+
// boolTransformFromPValue is a transformFunc that is capable of transforming PValueValue into BoolValue
50+
func boolTransformFromPValue(v PValueValue) (BoolValue, error) {
51+
val := v.Val()
52+
switch val.Type() {
53+
case pcommon.ValueTypeInt:
54+
return NewBoolValue(val.Int() != 0), nil
55+
case pcommon.ValueTypeDouble:
56+
return NewBoolValue(val.Double() != 0), nil
57+
case pcommon.ValueTypeStr:
58+
ret, err := strconv.ParseBool(val.Str())
59+
if err != nil {
60+
return nil, err
61+
}
62+
return NewBoolValue(ret), nil
63+
case pcommon.ValueTypeBool:
64+
return NewBoolValue(val.Bool()), nil
65+
default:
66+
return nil, fmt.Errorf("unsupported type conversion from pcommon.Value[%q] to \"bool\"", val.Type())
67+
}
68+
}
69+
70+
// boolTransformFromString is a transformFunc that is capable of transforming StringValue into BoolValue
71+
func boolTransformFromString(v StringValue) (BoolValue, error) {
72+
val, err := strconv.ParseBool(v.Val())
73+
if err != nil {
74+
return nil, err
75+
}
76+
return NewBoolValue(val), nil
77+
}
78+
79+
// boolTransformFromInt64 is a transformFunc that is capable of transforming Int64Value into BoolValue
80+
func boolTransformFromInt64(v Int64Value) (BoolValue, error) {
81+
return NewBoolValue(v.Val() != 0), nil
82+
}
83+
84+
// boolTransformFromFloat64 is a transformFunc that is capable of transforming Float64Value into BoolValue
85+
func boolTransformFromFloat64(v Float64Value) (BoolValue, error) {
86+
return NewBoolValue(v.Val() != 0), nil
87+
}

pkg/ottl/ottlruntime/bool_test.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ottlruntime
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
"go.opentelemetry.io/collector/pdata/pcommon"
12+
)
13+
14+
func TestToBoolValue(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
input Value
18+
expected bool
19+
isNil bool
20+
wantErr bool
21+
}{
22+
{
23+
name: "bool true",
24+
input: NewBoolValue(true),
25+
expected: true,
26+
},
27+
{
28+
name: "bool false",
29+
input: NewBoolValue(false),
30+
expected: false,
31+
},
32+
{
33+
name: "nil bool",
34+
input: NewNilBoolValue(),
35+
isNil: true,
36+
},
37+
{
38+
name: "string true",
39+
input: NewStringValue("true"),
40+
expected: true,
41+
},
42+
{
43+
name: "string false",
44+
input: NewStringValue("false"),
45+
expected: false,
46+
},
47+
{
48+
name: "invalid string",
49+
input: NewStringValue("not-a-bool"),
50+
wantErr: true,
51+
},
52+
{
53+
name: "int64 non-zero",
54+
input: NewInt64Value(1),
55+
expected: true,
56+
},
57+
{
58+
name: "int64 zero",
59+
input: NewInt64Value(0),
60+
expected: false,
61+
},
62+
{
63+
name: "float64 non-zero",
64+
input: NewFloat64Value(1.5),
65+
expected: true,
66+
},
67+
{
68+
name: "float64 zero",
69+
input: NewFloat64Value(0.0),
70+
expected: false,
71+
},
72+
{
73+
name: "pvalue int non-zero",
74+
input: NewPValueValue(pcommon.NewValueInt(10)),
75+
expected: true,
76+
},
77+
{
78+
name: "pvalue int zero",
79+
input: NewPValueValue(pcommon.NewValueInt(0)),
80+
expected: false,
81+
},
82+
{
83+
name: "pvalue double non-zero",
84+
input: NewPValueValue(pcommon.NewValueDouble(1.2)),
85+
expected: true,
86+
},
87+
{
88+
name: "pvalue double zero",
89+
input: NewPValueValue(pcommon.NewValueDouble(0.0)),
90+
expected: false,
91+
},
92+
{
93+
name: "pvalue string true",
94+
input: NewPValueValue(pcommon.NewValueStr("true")),
95+
expected: true,
96+
},
97+
{
98+
name: "pvalue string false",
99+
input: NewPValueValue(pcommon.NewValueStr("false")),
100+
expected: false,
101+
},
102+
{
103+
name: "pvalue invalid string",
104+
input: NewPValueValue(pcommon.NewValueStr("not-a-bool")),
105+
wantErr: true,
106+
},
107+
{
108+
name: "pvalue bool true",
109+
input: NewPValueValue(pcommon.NewValueBool(true)),
110+
expected: true,
111+
},
112+
{
113+
name: "pvalue bool false",
114+
input: NewPValueValue(pcommon.NewValueBool(false)),
115+
expected: false,
116+
},
117+
{
118+
name: "pvalue empty",
119+
input: NewPValueValue(pcommon.NewValueEmpty()),
120+
wantErr: true,
121+
},
122+
{
123+
name: "nil pvalue",
124+
input: NewNilPValueValue(),
125+
wantErr: true,
126+
},
127+
{
128+
name: "unsupported type (PMap)",
129+
input: NewPMapValue(pcommon.NewMap()),
130+
wantErr: true,
131+
},
132+
}
133+
134+
for _, tt := range tests {
135+
t.Run(tt.name, func(t *testing.T) {
136+
res, err := ToBoolValue(tt.input)
137+
if tt.wantErr {
138+
assert.Error(t, err)
139+
assert.Nil(t, res)
140+
return
141+
}
142+
143+
require.NoError(t, err)
144+
assert.Equal(t, tt.isNil, res.IsNil())
145+
if !tt.isNil {
146+
assert.Equal(t, tt.expected, res.Val())
147+
}
148+
})
149+
}
150+
}

pkg/ottl/ottlruntime/duration.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ottlruntime // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlruntime"
5+
6+
import (
7+
"fmt"
8+
"time"
9+
10+
"go.opentelemetry.io/collector/pdata/pcommon"
11+
)
12+
13+
type DurationValue interface {
14+
Value
15+
16+
// Val returns the underlying value, if IsNil is true this panics.
17+
Val() time.Duration
18+
}
19+
20+
func NewDurationValue(val time.Duration) DurationValue {
21+
return newValue(val, false)
22+
}
23+
24+
func NewNilDurationValue() DurationValue {
25+
return newValue(time.Duration(0), true)
26+
}
27+
28+
func ToDurationValue(v Value) (DurationValue, error) {
29+
if val, ok := v.(DurationValue); ok {
30+
return val, nil
31+
}
32+
if v.IsNil() {
33+
return nil, fmt.Errorf("unsupported type conversion from nil %T to \"DurationValue\"", v)
34+
}
35+
switch val := v.(type) {
36+
case DurationValue:
37+
return val, nil
38+
case StringValue:
39+
return durationTransformFromString(val)
40+
case Int64Value:
41+
return durationTransformFromInt64(val)
42+
case PValueValue:
43+
return durationTransformFromPValue(val)
44+
default:
45+
return nil, fmt.Errorf("unsupported type conversion from %T to \"duration\"", v)
46+
}
47+
}
48+
49+
func durationTransformFromPValue(v PValueValue) (DurationValue, error) {
50+
pv := v.Val()
51+
switch pv.Type() {
52+
case pcommon.ValueTypeInt:
53+
return NewDurationValue(time.Duration(pv.Int())), nil
54+
case pcommon.ValueTypeStr:
55+
d, err := time.ParseDuration(pv.Str())
56+
if err != nil {
57+
return nil, err
58+
}
59+
return NewDurationValue(d), nil
60+
default:
61+
return nil, fmt.Errorf("unsupported type conversion from pcommon.Value[%q] to \"duration\"", pv.Type())
62+
}
63+
}
64+
65+
func durationTransformFromString(v StringValue) (DurationValue, error) {
66+
d, err := time.ParseDuration(v.Val())
67+
if err != nil {
68+
return nil, err
69+
}
70+
return NewDurationValue(d), nil
71+
}
72+
73+
func durationTransformFromInt64(v Int64Value) (DurationValue, error) {
74+
return NewDurationValue(time.Duration(v.Val())), nil
75+
}

0 commit comments

Comments
 (0)