Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg/ottl] Add IntLikeGetter and use it in the Int Converter #22059

Merged
merged 5 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .chloggen/ottl-intlikegetter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: breaking

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: pkg/ottl

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Updates the `Int` converter to use a new `IntLikeGetter` which will error if the value cannot be converted to an int.

# One or more tracking issues related to the change
issues: [22059]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: |
Affected components: transformprocessor, filterprocessor, routingprocessor, tailsamplingprocessor, countconnector. It is HIGHLY recommended to use each component's error_mode configuration option to handle errors returned by `Int`.
4 changes: 4 additions & 0 deletions pkg/ottl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ The following types are supported for single-value parameters in OTTL functions:
- `FloatLikeGetter`
- `StringGetter`
- `StringLikeGetter`
- `IntGetter`
- `IntLikeGetter`
- `Enum`
- `string`
- `float64`
Expand All @@ -80,6 +82,8 @@ For slice parameters, the following types are supported:
- `FloatLikeGetter`
- `StringGetter`
- `StringLikeGetter`
- `IntGetter`
- `IntLikeGetter`
- `string`
- `float64`
- `int64`
Expand Down
64 changes: 64 additions & 0 deletions pkg/ottl/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,70 @@ func (g StandardFloatLikeGetter[K]) Get(ctx context.Context, tCtx K) (*float64,
return &result, nil
}

// IntLikeGetter is a Getter that returns an int by converting the underlying value to an int if necessary.
type IntLikeGetter[K any] interface {
// Get retrieves an int value.
// Unlike `IntGetter`, the expectation is that the underlying value is converted to an int if possible.
// If the value cannot be converted to an int, nil and an error are returned.
// If the value is nil, nil is returned without an error.
Get(ctx context.Context, tCtx K) (*int64, error)
}

type StandardIntLikeGetter[K any] struct {
Getter func(ctx context.Context, tCtx K) (interface{}, error)
}

func (g StandardIntLikeGetter[K]) Get(ctx context.Context, tCtx K) (*int64, error) {
val, err := g.Getter(ctx, tCtx)
if err != nil {
return nil, err
}
if val == nil {
return nil, nil
}
var result int64
switch v := val.(type) {
case int64:
result = v
case string:
result, err = strconv.ParseInt(v, 10, 64)
if err != nil {
return nil, nil
}
case float64:
result = int64(v)
case bool:
if v {
result = int64(1)
} else {
result = int64(0)
}
case pcommon.Value:
switch v.Type() {
case pcommon.ValueTypeInt:
result = v.Int()
case pcommon.ValueTypeDouble:
result = int64(v.Double())
case pcommon.ValueTypeStr:
result, err = strconv.ParseInt(v.Str(), 10, 64)
if err != nil {
return nil, nil
}
case pcommon.ValueTypeBool:
if v.Bool() {
result = int64(1)
} else {
result = int64(0)
}
default:
return nil, fmt.Errorf("unsupported value type: %v", v.Type())
}
default:
return nil, fmt.Errorf("unsupported type: %T", v)
}
return &result, nil
}

func (p *Parser[K]) newGetter(val value) (Getter[K], error) {
if val.IsNil != nil && *val.IsNil {
return &literal[K]{value: nil}, nil
Expand Down
163 changes: 163 additions & 0 deletions pkg/ottl/expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -971,3 +971,166 @@ func Test_StandardFloatLikeGetter(t *testing.T) {
})
}
}

func Test_StandardIntLikeGetter(t *testing.T) {
tests := []struct {
name string
getter IntLikeGetter[interface{}]
want interface{}
valid bool
expectedErrorMsg string
}{
{
name: "string type",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return "1", nil
},
},
want: int64(1),
valid: true,
},
{
name: "int64 type",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return int64(1), nil
},
},
want: int64(1),
valid: true,
},
{
name: "float64 type",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return 1.1, nil
},
},
want: int64(1),
valid: true,
},
{
name: "float64 bool true",
TylerHelmuth marked this conversation as resolved.
Show resolved Hide resolved
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return true, nil
},
},
want: int64(1),
valid: true,
},
{
name: "float64 bool false",
TylerHelmuth marked this conversation as resolved.
Show resolved Hide resolved
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return false, nil
},
},
want: int64(0),
valid: true,
},
{
name: "pcommon.value type int",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueInt(int64(100))
return v, nil
},
},
want: int64(100),
valid: true,
},
{
name: "pcommon.value type float",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueDouble(float64(1.9))
return v, nil
},
},
want: int64(1),
valid: true,
},
{
name: "pcommon.value type string",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueStr("1")
return v, nil
},
},
want: int64(1),
valid: true,
},
{
name: "pcommon.value type bool true",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueBool(true)
return v, nil
},
},
want: int64(1),
valid: true,
},
{
name: "pcommon.value type bool false",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueBool(false)
return v, nil
},
},
want: int64(0),
valid: true,
},
{
name: "nil",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return nil, nil
},
},
want: nil,
valid: true,
},
{
name: "invalid type",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return []byte{}, nil
},
},
valid: false,
expectedErrorMsg: "unsupported type: []uint8",
},
{
name: "invalid pcommon.Value type",
getter: StandardIntLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueMap()
return v, nil
},
},
valid: false,
expectedErrorMsg: "unsupported value type: Map",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
val, err := tt.getter.Get(context.Background(), nil)
if tt.valid {
assert.NoError(t, err)
if tt.want == nil {
assert.Nil(t, val)
} else {
assert.Equal(t, tt.want, *val)
}
} else {
assert.EqualError(t, err, tt.expectedErrorMsg)
}
})
}
}
18 changes: 18 additions & 0 deletions pkg/ottl/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ func (p *Parser[K]) buildSliceArg(argVal value, argType reflect.Type) (any, erro
return nil, err
}
return arg, nil
case strings.HasPrefix(name, "IntGetter"):
arg, err := buildSlice[IntGetter[K]](argVal, argType, p.buildArg, name)
if err != nil {
return nil, err
}
return arg, nil
case strings.HasPrefix(name, "IntLikeGetter"):
arg, err := buildSlice[IntLikeGetter[K]](argVal, argType, p.buildArg, name)
if err != nil {
return nil, err
}
return arg, nil
default:
return nil, fmt.Errorf("unsupported slice type '%s' for function", argType.Elem().Name())
}
Expand Down Expand Up @@ -223,6 +235,12 @@ func (p *Parser[K]) buildArg(argVal value, argType reflect.Type) (any, error) {
return nil, err
}
return StandardTypeGetter[K, int64]{Getter: arg.Get}, nil
case strings.HasPrefix(name, "IntLikeGetter"):
arg, err := p.newGetter(argVal)
if err != nil {
return nil, err
}
return StandardIntLikeGetter[K]{Getter: arg.Get}, nil
case strings.HasPrefix(name, "PMapGetter"):
arg, err := p.newGetter(argVal)
if err != nil {
Expand Down
Loading