Skip to content

Commit

Permalink
Merge pull request #7267 from dolthub/bh/walk
Browse files Browse the repository at this point in the history
recursively walk the fields of structs
  • Loading branch information
bheni authored Jan 6, 2024
2 parents f3d20a2 + 5bd9f78 commit 6b6de81
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 1 deletion.
65 changes: 65 additions & 0 deletions go/libraries/utils/structwalk/walk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2024 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package structwalk

import (
"reflect"
)

func Walk(v any, f func(sf reflect.StructField, depth int) error) error {
return walkStruct(v, 0, f)
}

func walkStruct(v any, depth int, f func(sf reflect.StructField, depth int) error) error {
t := reflect.TypeOf(v)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}

return walkFields(t, depth, f)
}

func walkFields(t reflect.Type, depth int, f func(sf reflect.StructField, depth int) error) error {
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
err := processField(field, depth, f)
if err != nil {
return err
}
}

return nil
}

func processField(field reflect.StructField, depth int, f func(sf reflect.StructField, depth int) error) error {
if err := f(field, depth); err != nil {
return err
}

if field.Type.Kind() == reflect.Ptr || field.Type.Kind() == reflect.Slice {
if field.Type.Elem().Kind() == reflect.Struct {
t := field.Type.Elem()
if err := walkFields(t, depth+1, f); err != nil {
return err
}
}
} else if field.Type.Kind() == reflect.Struct {
if err := walkFields(field.Type, depth+1, f); err != nil {
return err
}
}

return nil
}
93 changes: 93 additions & 0 deletions go/libraries/utils/structwalk/walk_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2024 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package structwalk

import (
"reflect"
"testing"

"github.com/stretchr/testify/require"
)

func TestWalk(t *testing.T) {
type innerStruct struct {
Five *string `json:"five"`
}

type testStruct struct {
One string `json:"one"`
Two int `json:"two"`
Three bool `json:"three"`
Four *innerStruct `json:"four"`
Six []string `json:"six"`
}

expected := []struct {
name string
typeStr string
depth int
json string
}{
{
name: "One",
typeStr: "string",
depth: 0,
json: "one",
},
{
name: "Two",
typeStr: "int",
depth: 0,
json: "two",
},
{
name: "Three",
typeStr: "bool",
depth: 0,
json: "three",
},
{
name: "Four",
typeStr: "*structwalk.innerStruct",
depth: 0,
json: "four",
},
{
name: "Five",
typeStr: "*string",
depth: 1,
json: "five",
},
{
name: "Six",
typeStr: "[]string",
depth: 0,
json: "six",
},
}

var n int
err := Walk(&testStruct{}, func(sf reflect.StructField, depth int) error {
require.Equal(t, expected[n].name, sf.Name)
require.Equal(t, expected[n].typeStr, sf.Type.String())
require.Equal(t, expected[n].depth, depth)
require.Equal(t, expected[n].json, sf.Tag.Get("json"))
n++
return nil
})

require.NoError(t, err)
require.Equal(t, len(expected), n)
}
2 changes: 1 addition & 1 deletion go/utils/copyrightshdrs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"strings"
)

var ExpectedHeader = regexp.MustCompile(`// Copyright (2019|2020|2021|2022|2023|2019-2020|2019-2021|2019-2022|2019-2023|2020-2021|2020-2022|2020-2023|2021-2022|2021-2023|2022-2023) Dolthub, Inc.
var ExpectedHeader = regexp.MustCompile(`// Copyright (2019|2020|2021|2022|2023|2024|2019-2020|2019-2021|2019-2022|2019-2023|2019-2024|2020-2021|2020-2022|2020-2023|2020-2024|2021-2022|2021-2023|2021-2024|2022-2023|2022-2024|2023-2024) Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 \(the "License"\);
// you may not use this file except in compliance with the License.
Expand Down

0 comments on commit 6b6de81

Please sign in to comment.