Skip to content

Commit a92ca2e

Browse files
authored
Merge pull request #682 from nginx-proxy/fix/679
fix(reflect): handle deep get of map with dot(s) in key name
2 parents 264523d + 386f927 commit a92ca2e

File tree

4 files changed

+49
-2
lines changed

4 files changed

+49
-2
lines changed

internal/template/reflect.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,24 @@ func deepGetImpl(v reflect.Value, path []string) interface{} {
4141
case reflect.Struct:
4242
return deepGetImpl(v.FieldByName(path[0]), path[1:])
4343
case reflect.Map:
44-
return deepGetImpl(v.MapIndex(reflect.ValueOf(path[0])), path[1:])
44+
// If the first part of the path is a key in the map, we use it directly
45+
if mapValue := v.MapIndex(reflect.ValueOf(path[0])); mapValue.IsValid() {
46+
return deepGetImpl(mapValue, path[1:])
47+
}
48+
49+
// If the first part of the path is not a key in the map, we try to find a valid key by joining the path parts
50+
for i := 2; i <= len(path); i++ {
51+
joinedPath := strings.Join(path[0:i], ".")
52+
if mapValue := v.MapIndex(reflect.ValueOf(joinedPath)); mapValue.IsValid() {
53+
if i == len(path) {
54+
return mapValue.Interface()
55+
}
56+
return deepGetImpl(mapValue, path[i:])
57+
}
58+
}
59+
60+
log.Printf("unable to find key from the path expression %s in map %v\n", strings.Join(path, "."), v)
61+
return nil
4562
case reflect.Slice, reflect.Array:
4663
i, err := parseAllocateInt(path[0])
4764
if err != nil {

internal/template/reflect_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,28 @@ func TestDeepGet(t *testing.T) {
7474
"...",
7575
"foo",
7676
},
77+
{
78+
"map with dot in key",
79+
map[string]map[string]string{
80+
"Foo": {
81+
"foo.bar.baz.qux": "quux",
82+
},
83+
},
84+
"Foo.foo.bar.baz.qux",
85+
"quux",
86+
},
87+
{
88+
"nested maps with dot in keys",
89+
map[string]map[string]map[string]string{
90+
"Foo": {
91+
"foo.bar": {
92+
"baz.qux": "quux",
93+
},
94+
},
95+
},
96+
"Foo.foo.bar.baz.qux",
97+
"quux",
98+
},
7799
{"struct", s, "X", "foo"},
78100
{"pointer to struct", sp, "X", "foo"},
79101
{"double pointer to struct", &sp, ".X", nil},

internal/template/sort.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ func getFieldAsString(item interface{}, path string) string {
9090
func (s sortableByKey) Less(i, j int) bool {
9191
dataI := getFieldAsString(s.data[i], s.key)
9292
dataJ := getFieldAsString(s.data[j], s.key)
93+
94+
if intI, err := strconv.ParseInt(dataI, 10, 64); err == nil {
95+
if intJ, err := strconv.ParseInt(dataJ, 10, 64); err == nil {
96+
// If both are integers, compare as integers
97+
return intI < intJ
98+
}
99+
}
100+
93101
return dataI < dataJ
94102
}
95103

internal/template/sort_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func TestSortObjectsByKeys(t *testing.T) {
5555
Env: map[string]string{
5656
"VIRTUAL_HOST": "bar.localhost",
5757
},
58-
ID: "9",
58+
ID: "11",
5959
}
6060
o1 := &context.RuntimeContainer{
6161
Created: time.Date(2021, 1, 2, 0, 0, 10, 0, time.UTC),

0 commit comments

Comments
 (0)