Skip to content

Commit 8b99177

Browse files
committed
Merge pull request #83 from appropriate/generalize-where
Generalize where* functions
2 parents 84d11f0 + 3ce30e4 commit 8b99177

File tree

5 files changed

+148
-170
lines changed

5 files changed

+148
-170
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ Within those templates, the object emitted by docker-gen will have [this structu
134134
* *`split $string $sep`*: Splits `$string` into a slice of substrings delimited by `$sep`. Alias for [`strings.Split`](http://golang.org/pkg/strings/#Split)
135135
* *`trimPrefix $prefix $string`*: If `$prefix` is a prefix of `$string`, return `$string` with `$prefix` trimmed from the beginning. Otherwise, return `$string` unchanged.
136136
* *`trimSuffix $suffix $string`*: If `$suffix` is a suffix of `$string`, return `$string` with `$suffix` trimmed from the end. Otherwise, return `$string` unchanged.
137-
* *`where $containers $fieldPath $value`*: Filters an array of `RuntimeContainer` instances based on the values of a field path expression `$fieldPath`. A field path expression is a dot-delimited list of map keys or struct member names specifying the path from container to a nested value, which must be a string. Returns an array of containers having that value.
138-
* *`whereExist $containers $fieldPath`*: Like `where`, but returns only containers where `$fieldPath` exists (is not nil).
139-
* *`whereNotExist $containers $fieldPath`*: Like `where`, but returns only containers where `$fieldPath` does not exist (is nil).
140-
* *`whereAny $containers $fieldPath $sep $values`*: Like `where`, but the string value specified by `$fieldPath` is first split by `$sep` into a list of strings. The comparison value is a string slice with possible matches. Returns containers which OR intersect these values.
141-
* *`whereAll $containers $fieldPath $sep $values`*: Like `whereAny`, except all `$values` must exist in the `$fieldPath`.
137+
* *`where $items $fieldPath $value`*: Filters an array or slice based on the values of a field path expression `$fieldPath`. A field path expression is a dot-delimited list of map keys or struct member names specifying the path from container to a nested value. Returns an array of items having that value.
138+
* *`whereExist $items $fieldPath`*: Like `where`, but returns only items where `$fieldPath` exists (is not nil).
139+
* *`whereNotExist $items $fieldPath`*: Like `where`, but returns only items where `$fieldPath` does not exist (is nil).
140+
* *`whereAny $items $fieldPath $sep $values`*: Like `where`, but the string value specified by `$fieldPath` is first split by `$sep` into a list of strings. The comparison value is a string slice with possible matches. Returns items which OR intersect these values.
141+
* *`whereAll $items $fieldPath $sep $values`*: Like `whereAny`, except all `$values` must exist in the `$fieldPath`.
142142

143143
===
144144

reflect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func deepGet(item interface{}, path string) interface{} {
4040
return deepGet(mapValue.Interface(), strings.Join(parts[1:], "."))
4141
}
4242
default:
43-
log.Printf("can't group by %s\n", path)
43+
log.Printf("can't group by %s (value %v, kind %s)\n", path, itemValue, itemValue.Kind())
4444
}
4545
return nil
4646
}

template.go

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -66,71 +66,74 @@ func groupByKeys(entries []*RuntimeContainer, key string) []string {
6666
return ret
6767
}
6868

69-
// selects entries based on key
70-
func where(entries []*RuntimeContainer, key string, cmp string) []*RuntimeContainer {
71-
selection := []*RuntimeContainer{}
72-
for _, v := range entries {
73-
value := deepGet(*v, key)
74-
if value == cmp {
69+
// Generalized where function
70+
func generalizedWhere(funcName string, entries interface{}, key string, test func(interface{}) bool) (interface{}, error) {
71+
entriesVal := reflect.ValueOf(entries)
72+
73+
switch entriesVal.Kind() {
74+
case reflect.Array, reflect.Slice:
75+
break
76+
default:
77+
return nil, fmt.Errorf("Must pass an array or slice to '%s'; received %v", funcName, entries)
78+
}
79+
80+
selection := make([]interface{}, 0)
81+
for i := 0; i < entriesVal.Len(); i++ {
82+
v := reflect.Indirect(entriesVal.Index(i)).Interface()
83+
84+
value := deepGet(v, key)
85+
if test(value) {
7586
selection = append(selection, v)
7687
}
7788
}
78-
return selection
89+
90+
return selection, nil
91+
}
92+
93+
// selects entries based on key
94+
func where(entries interface{}, key string, cmp interface{}) (interface{}, error) {
95+
return generalizedWhere("where", entries, key, func(value interface{}) bool {
96+
return reflect.DeepEqual(value, cmp)
97+
})
7998
}
8099

81100
// selects entries where a key exists
82-
func whereExist(entries []*RuntimeContainer, key string) []*RuntimeContainer {
83-
selection := []*RuntimeContainer{}
84-
for _, v := range entries {
85-
value := deepGet(*v, key)
86-
if value != nil {
87-
selection = append(selection, v)
88-
}
89-
}
90-
return selection
101+
func whereExist(entries interface{}, key string) (interface{}, error) {
102+
return generalizedWhere("whereExist", entries, key, func(value interface{}) bool {
103+
return value != nil
104+
})
91105
}
92106

93107
// selects entries where a key does not exist
94-
func whereNotExist(entries []*RuntimeContainer, key string) []*RuntimeContainer {
95-
selection := []*RuntimeContainer{}
96-
for _, v := range entries {
97-
value := deepGet(*v, key)
98-
if value == nil {
99-
selection = append(selection, v)
100-
}
101-
}
102-
return selection
108+
func whereNotExist(entries interface{}, key string) (interface{}, error) {
109+
return generalizedWhere("whereNotExist", entries, key, func(value interface{}) bool {
110+
return value == nil
111+
})
103112
}
104113

105114
// selects entries based on key. Assumes key is delimited and breaks it apart before comparing
106-
func whereAny(entries []*RuntimeContainer, key, sep string, cmp []string) []*RuntimeContainer {
107-
selection := []*RuntimeContainer{}
108-
for _, v := range entries {
109-
value := deepGet(*v, key)
110-
if value != nil {
115+
func whereAny(entries interface{}, key, sep string, cmp []string) (interface{}, error) {
116+
return generalizedWhere("whereAny", entries, key, func(value interface{}) bool {
117+
if value == nil {
118+
return false
119+
} else {
111120
items := strings.Split(value.(string), sep)
112-
if len(intersect(cmp, items)) > 0 {
113-
selection = append(selection, v)
114-
}
121+
return len(intersect(cmp, items)) > 0
115122
}
116-
}
117-
return selection
123+
})
118124
}
119125

120126
// selects entries based on key. Assumes key is delimited and breaks it apart before comparing
121-
func whereAll(entries []*RuntimeContainer, key, sep string, cmp []string) []*RuntimeContainer {
122-
selection := []*RuntimeContainer{}
127+
func whereAll(entries interface{}, key, sep string, cmp []string) (interface{}, error) {
123128
req_count := len(cmp)
124-
for _, v := range entries {
125-
value := deepGet(*v, key)
126-
if value != nil {
129+
return generalizedWhere("whereAll", entries, key, func(value interface{}) bool {
130+
if value == nil {
131+
return false
132+
} else {
127133
items := strings.Split(value.(string), sep)
128-
if len(intersect(cmp, items)) == req_count {
129-
selection = append(selection, v)
130-
}
134+
return len(intersect(cmp, items)) == req_count
131135
}
132-
}
133-
return selection
136+
})
134137
}
135138

136139
// hasPrefix returns whether a given string is a prefix of another string

0 commit comments

Comments
 (0)