Skip to content

Instantly share code, notes, and snippets.

@GerardRodes
Last active June 27, 2022 10:59
Show Gist options
  • Save GerardRodes/6a0a2c9f22fd80fcfe66f776bbfb3be4 to your computer and use it in GitHub Desktop.
Save GerardRodes/6a0a2c9f22fd80fcfe66f776bbfb3be4 to your computer and use it in GitHub Desktop.
Go - get field value by tag value
package main
import (
"errors"
"reflect"
)
func GetFieldValueByTagValue[T any](instance any, tagname, tagvalue string) (T, error) {
var noop T
if tagname == "" {
return noop, errors.New("tagname cannot be empty")
}
if tagvalue == "" {
return noop, errors.New("tagvalue cannot be empty")
}
v := reflect.TypeOf(instance)
for i := 0; i < v.NumField(); i++ {
iField := reflect.ValueOf(instance).Field(i).Interface()
if v.Field(i).Tag.Get(tagname) == tagvalue {
if v, ok := iField.(T); ok {
return v, nil
}
} else if v.Field(i).Type.Kind() == reflect.Struct {
v, err := GetFieldValueByTagValue[T](iField, tagname, tagvalue)
if err == nil {
return v, nil
}
}
}
return noop, errors.New("not found")
}
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetFieldValueByTagValue(t *testing.T) {
type Embedded struct {
Field string `foo:"Embedded.Field"`
}
type Nested struct {
Field string `foo:"Nested.Field"`
}
type Base struct {
Field string `foo:"Base.Field"`
Nested Nested `foo:"Base.Nested"`
Embedded `foo:"Base.Embedded"`
}
a := Base{
Field: "Base.Field value",
Nested: Nested{"Nested.Field value"},
Embedded: Embedded{"Embedded.Field value"},
}
t.Run("get string", func(t *testing.T) {
v, err := GetFieldValueByTagValue[string](a, "foo", "Base.Field")
assert.NoError(t, err)
assert.Equal(t, v, "Base.Field value")
})
t.Run("get custom type", func(t *testing.T) {
v, err := GetFieldValueByTagValue[Nested](a, "foo", "Base.Nested")
assert.NoError(t, err)
assert.Equal(t, v, Nested{"Nested.Field value"})
})
t.Run("get nested field", func(t *testing.T) {
v, err := GetFieldValueByTagValue[string](a, "foo", "Nested.Field")
assert.NoError(t, err)
assert.Equal(t, v, "Nested.Field value")
})
t.Run("get embedded", func(t *testing.T) {
v, err := GetFieldValueByTagValue[Embedded](a, "foo", "Base.Embedded")
assert.NoError(t, err)
assert.Equal(t, v, Embedded{"Embedded.Field value"})
})
t.Run("get embedded field", func(t *testing.T) {
v, err := GetFieldValueByTagValue[string](a, "foo", "Embedded.Field")
assert.NoError(t, err)
assert.Equal(t, v, "Embedded.Field value")
})
t.Run("not found", func(t *testing.T) {
_, err := GetFieldValueByTagValue[string](a, "zzz", "zzz")
assert.EqualError(t, err, "not found")
_, err = GetFieldValueByTagValue[string](a, "foo", "zzz")
assert.EqualError(t, err, "not found")
_, err = GetFieldValueByTagValue[string](a, "foo", "Base.Nested")
assert.EqualError(t, err, "not found")
})
t.Run("tagname empty", func(t *testing.T) {
_, err := GetFieldValueByTagValue[string](a, "", "zzz")
assert.EqualError(t, err, "tagname cannot be empty")
})
t.Run("tagvalue empty", func(t *testing.T) {
_, err := GetFieldValueByTagValue[string](a, "zzz", "")
assert.EqualError(t, err, "tagvalue cannot be empty")
})
t.Run("type not matching", func(t *testing.T) {
_, err := GetFieldValueByTagValue[int](a, "foo", "Base.Field")
assert.EqualError(t, err, "not found")
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment