blob: 8efb283e7290ec417b08d2c6f9e0cd59aace617c [file] [log] [blame]
Joe Topjian1e9551c2017-06-03 10:35:33 -06001package internal
2
3import (
4 "reflect"
Joe Topjianfb5c0e82017-06-10 20:52:58 -06005 "strings"
Joe Topjian1e9551c2017-06-03 10:35:33 -06006)
7
Joe Topjianfb5c0e82017-06-10 20:52:58 -06008// RemainingKeys will inspect a struct and compare it to a map. Any struct
9// field that does not have a JSON tag that matches a key in the map or
10// a matching lower-case field in the map will be returned as an extra.
Joe Topjian1e9551c2017-06-03 10:35:33 -060011//
12// This is useful for determining the extra fields returned in response bodies
13// for resources that can contain an arbitrary or dynamic number of fields.
14func RemainingKeys(s interface{}, m map[string]interface{}) (extras map[string]interface{}) {
15 extras = make(map[string]interface{})
Joe Topjianfb5c0e82017-06-10 20:52:58 -060016 for k, v := range m {
17 extras[k] = v
18 }
19
Joe Topjian1e9551c2017-06-03 10:35:33 -060020 valueOf := reflect.ValueOf(s)
21 typeOf := reflect.TypeOf(s)
22 for i := 0; i < valueOf.NumField(); i++ {
23 field := typeOf.Field(i)
Joe Topjianfb5c0e82017-06-10 20:52:58 -060024
25 lowerField := strings.ToLower(field.Name)
26 delete(extras, lowerField)
27
28 if tagValue := field.Tag.Get("json"); tagValue != "" && tagValue != "-" {
29 delete(extras, tagValue)
Joe Topjian1e9551c2017-06-03 10:35:33 -060030 }
31 }
32
33 return
34}