Skip to content

Commit 3e80765

Browse files
authored
Merge pull request #578 from nginx-proxy/multi-type-sort
feat: sortObjectsByKeys with types other than string
2 parents 0aff309 + 2c152ba commit 3e80765

File tree

2 files changed

+75
-9
lines changed

2 files changed

+75
-9
lines changed

internal/template/sort.go

+37-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package template
33
import (
44
"reflect"
55
"sort"
6+
"strconv"
7+
"time"
68
)
79

810
// sortStrings returns a sorted array of strings in increasing order
@@ -52,15 +54,43 @@ func (s *sortableByKey) set(funcName string, entries interface{}) (err error) {
5254
return
5355
}
5456

55-
// method required to implement sort.Interface
56-
func (s sortableByKey) Less(i, j int) bool {
57-
values := map[int]string{i: "", j: ""}
58-
for k := range values {
59-
if v := reflect.ValueOf(deepGet(s.data[k], s.key)); v.Kind() != reflect.Invalid {
60-
values[k] = v.Interface().(string)
57+
func getFieldAsString(item interface{}, path string) string {
58+
// Mostly inspired by https://stackoverflow.com/a/47739620
59+
e := deepGet(item, path)
60+
r := reflect.ValueOf(e)
61+
62+
if r.Kind() == reflect.Invalid {
63+
return ""
64+
}
65+
66+
fieldValue := r.Interface()
67+
68+
switch v := fieldValue.(type) {
69+
case int:
70+
return strconv.FormatInt(int64(v), 10)
71+
case int32:
72+
return strconv.FormatInt(int64(v), 10)
73+
case int64:
74+
return strconv.FormatInt(v, 10)
75+
case string:
76+
return v
77+
case bool:
78+
if v {
79+
return "true"
6180
}
81+
return "false"
82+
case time.Time:
83+
return v.String()
84+
default:
85+
return ""
6286
}
63-
return values[i] < values[j]
87+
}
88+
89+
// method required to implement sort.Interface
90+
func (s sortableByKey) Less(i, j int) bool {
91+
dataI := getFieldAsString(s.data[i], s.key)
92+
dataJ := getFieldAsString(s.data[j], s.key)
93+
return dataI < dataJ
6494
}
6595

6696
// Generalized SortBy function

internal/template/sort_test.go

+38-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package template
22

33
import (
44
"testing"
5+
"time"
56

67
"github.com/nginx-proxy/docker-gen/internal/context"
78
"github.com/stretchr/testify/assert"
@@ -19,28 +20,61 @@ func TestSortStringsDesc(t *testing.T) {
1920
assert.Equal(t, expected, sortStringsDesc(strings))
2021
}
2122

23+
func TestGetFieldAsString(t *testing.T) {
24+
testStruct := struct {
25+
String string
26+
BoolT bool
27+
BoolF bool
28+
Int int
29+
Int32 int32
30+
Int64 int64
31+
Time time.Time
32+
}{
33+
String: "foo",
34+
BoolT: true,
35+
BoolF: false,
36+
Int: 42,
37+
Int32: 43,
38+
Int64: 44,
39+
Time: time.Date(2023, 12, 19, 0, 0, 0, 0, time.UTC),
40+
}
41+
42+
assert.Equal(t, "foo", getFieldAsString(testStruct, "String"))
43+
assert.Equal(t, "true", getFieldAsString(testStruct, "BoolT"))
44+
assert.Equal(t, "false", getFieldAsString(testStruct, "BoolF"))
45+
assert.Equal(t, "42", getFieldAsString(testStruct, "Int"))
46+
assert.Equal(t, "43", getFieldAsString(testStruct, "Int32"))
47+
assert.Equal(t, "44", getFieldAsString(testStruct, "Int64"))
48+
assert.Equal(t, "2023-12-19 00:00:00 +0000 UTC", getFieldAsString(testStruct, "Time"))
49+
assert.Equal(t, "", getFieldAsString(testStruct, "InvalidField"))
50+
}
51+
2252
func TestSortObjectsByKeys(t *testing.T) {
2353
o0 := &context.RuntimeContainer{
54+
Created: time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC),
2455
Env: map[string]string{
2556
"VIRTUAL_HOST": "bar.localhost",
2657
},
2758
ID: "9",
2859
}
2960
o1 := &context.RuntimeContainer{
61+
Created: time.Date(2021, 1, 2, 0, 0, 10, 0, time.UTC),
3062
Env: map[string]string{
3163
"VIRTUAL_HOST": "foo.localhost",
3264
},
3365
ID: "1",
3466
}
3567
o2 := &context.RuntimeContainer{
68+
Created: time.Date(2021, 1, 2, 0, 0, 0, 0, time.UTC),
3669
Env: map[string]string{
3770
"VIRTUAL_HOST": "baz.localhost",
3871
},
3972
ID: "3",
4073
}
4174
o3 := &context.RuntimeContainer{
42-
Env: map[string]string{},
43-
ID: "8",
75+
Created: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
76+
Env: map[string]string{},
77+
ID: "8",
4478
}
4579
containers := []*context.RuntimeContainer{o0, o1, o2, o3}
4680

@@ -54,6 +88,8 @@ func TestSortObjectsByKeys(t *testing.T) {
5488
{"Asc complex", sortObjectsByKeysAsc, "Env.VIRTUAL_HOST", []interface{}{o3, o0, o2, o1}},
5589
{"Desc simple", sortObjectsByKeysDesc, "ID", []interface{}{o0, o3, o2, o1}},
5690
{"Desc complex", sortObjectsByKeysDesc, "Env.VIRTUAL_HOST", []interface{}{o1, o2, o0, o3}},
91+
{"Asc time", sortObjectsByKeysAsc, "Created", []interface{}{o3, o0, o2, o1}},
92+
{"Desc time", sortObjectsByKeysDesc, "Created", []interface{}{o1, o2, o0, o3}},
5793
} {
5894
t.Run(tc.desc, func(t *testing.T) {
5995
got, err := tc.fn(containers, tc.key)

0 commit comments

Comments
 (0)