diff --git a/go/libraries/utils/structwalk/walk.go b/go/libraries/utils/structwalk/walk.go new file mode 100644 index 00000000000..b1990ff27dd --- /dev/null +++ b/go/libraries/utils/structwalk/walk.go @@ -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 +} diff --git a/go/libraries/utils/structwalk/walk_test.go b/go/libraries/utils/structwalk/walk_test.go new file mode 100644 index 00000000000..df10eb0a41a --- /dev/null +++ b/go/libraries/utils/structwalk/walk_test.go @@ -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) +} diff --git a/go/utils/copyrightshdrs/main.go b/go/utils/copyrightshdrs/main.go index c5a978d81ed..623b71749bc 100644 --- a/go/utils/copyrightshdrs/main.go +++ b/go/utils/copyrightshdrs/main.go @@ -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.