@@ -40,19 +40,13 @@ func Walk(s interface{}, callback CallbackFunc) {
4040 }
4141}
4242
43- // FilterStruct filters the struct based on include and exclude fields and returns a new struct.
44- // - input: the original struct.
45- // - includeFields: list of fields to include (if empty, includes all).
46- // - excludeFields: list of fields to exclude (processed after include).
47- func FilterStruct [T any ](input T , includeFields , excludeFields []string ) (T , error ) {
48- var zeroValue T
43+ func walkFilteredFields [T any ](input T , includeFields , excludeFields []string , walker func (field reflect.StructField , value reflect.Value )) error {
4944 val := reflect .ValueOf (input )
5045 if val .Kind () == reflect .Ptr {
5146 val = val .Elem ()
5247 }
53-
5448 if val .Kind () != reflect .Struct {
55- return zeroValue , errors .New ("input must be a struct" )
49+ return errors .New ("input must be a struct" )
5650 }
5751
5852 includeMap := make (map [string ]bool )
@@ -66,7 +60,6 @@ func FilterStruct[T any](input T, includeFields, excludeFields []string) (T, err
6660 }
6761
6862 typeOfStruct := val .Type ()
69- filteredStruct := reflect .New (typeOfStruct ).Elem ()
7063
7164 for i := 0 ; i < val .NumField (); i ++ {
7265 field := typeOfStruct .Field (i )
@@ -77,13 +70,62 @@ func FilterStruct[T any](input T, includeFields, excludeFields []string) (T, err
7770 fieldValue := val .Field (i )
7871
7972 if (len (includeMap ) == 0 || includeMap [fieldName ]) && ! excludeMap [fieldName ] {
80- filteredStruct . Field ( i ). Set ( fieldValue )
73+ walker ( field , fieldValue )
8174 }
8275 }
76+ return nil
77+ }
78+
79+ // FilterStruct filters the struct based on include and exclude fields and returns a new struct.
80+ // - input: the original struct.
81+ // - includeFields: list of fields to include (if empty, includes all).
82+ // - excludeFields: list of fields to exclude (processed after include).
83+ func FilterStruct [T any ](input T , includeFields , excludeFields []string ) (T , error ) {
84+ var zeroValue T
85+ val := reflect .ValueOf (input )
86+ if val .Kind () == reflect .Ptr {
87+ val = val .Elem ()
88+ }
89+
90+ filteredStruct := reflect .New (val .Type ()).Elem ()
91+
92+ walker := func (field reflect.StructField , value reflect.Value ) {
93+ filteredStruct .FieldByName (field .Name ).Set (value )
94+ }
95+
96+ if err := walkFilteredFields (input , includeFields , excludeFields , walker ); err != nil {
97+ return zeroValue , err
98+ }
8399
84100 return filteredStruct .Interface ().(T ), nil
85101}
86102
103+ func FilterStructToMap [T any ](input T , includeFields , excludeFields []string ) (map [string ]any , error ) {
104+ resultMap := make (map [string ]any )
105+
106+ walker := func (field reflect.StructField , value reflect.Value ) {
107+ jsonTag := field .Tag .Get ("json" )
108+ jsonKey := strings .Split (jsonTag , "," )[0 ]
109+
110+ if jsonKey == "" || jsonKey == "-" {
111+ return
112+ }
113+
114+ fieldValue := value .Interface ()
115+ if strings .Contains (jsonTag , "omitempty" ) && value .IsZero () {
116+ return
117+ }
118+
119+ resultMap [jsonKey ] = fieldValue
120+ }
121+
122+ if err := walkFilteredFields (input , includeFields , excludeFields , walker ); err != nil {
123+ return nil , err
124+ }
125+
126+ return resultMap , nil
127+ }
128+
87129// GetStructFields returns all the top-level field names from the given struct.
88130// - input: the original struct.
89131// Returns a slice of field names or an error if the input is not a struct.
0 commit comments