Skip to content

Instantly share code, notes, and snippets.

@gruzovator
Created November 13, 2019 07:23
Show Gist options
  • Save gruzovator/f123cde97a10796e8556f2500cc3919b to your computer and use it in GitHub Desktop.
Save gruzovator/f123cde97a10796e8556f2500cc3919b to your computer and use it in GitHub Desktop.
golang runtime struct fields filtering
package main
import (
"fmt"
"net/http"
"reflect"
"strings"
)
type Person struct {
ID string
Name string
Age int
Address string
}
func main() {
var personStore = map[string]*Person{
"1": {
ID: "1",
Name: "Person A",
Age: 42,
Address: "RU",
},
"2": {
ID: "2",
Name: "Person B",
Age: 24,
Address: "UR",
},
}
fieldsIdx := newStructFieldsIdx(Person{})
http.HandleFunc("/persons/", func(w http.ResponseWriter, r *http.Request) {
personID := r.URL.Path[9:]
p, ok := personStore[personID]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
fieldsToSelect := r.URL.Query()["field"]
if len(fieldsToSelect) == 0 {
fmt.Fprintf(w, "%+v\n", p)
return
}
fmt.Fprintf(w, "%+v\n", fieldsIdx.Filter(p, fieldsToSelect))
})
http.ListenAndServe(":8080", nil)
}
type structFieldsIndex struct {
t reflect.Type
fieldsByLcName map[string]reflect.StructField
}
func newStructFieldsIdx(structIntstance interface{}) *structFieldsIndex {
t := reflect.TypeOf(structIntstance)
idx := make(map[string]reflect.StructField)
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
idx[strings.ToLower(f.Name)] = f
}
return &structFieldsIndex{
t: t,
fieldsByLcName: idx,
}
}
func (idx *structFieldsIndex) Filter(structInstance interface{}, fields []string) interface{} {
elem := reflect.ValueOf(structInstance).Elem()
ff := make([]reflect.StructField, 0, len(fields))
vv := make([]reflect.Value, 0, len(fields))
for _, name := range fields {
f, ok := idx.fieldsByLcName[strings.ToLower(name)]
if !ok {
continue
}
ff = append(ff, f)
vv = append(vv, elem.FieldByIndex(f.Index))
}
r := reflect.New(reflect.StructOf(ff)).Elem()
for i, v := range vv {
r.Field(i).Set(v)
}
return r.Addr().Interface()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment