Skip to content

Commit 15dd68c

Browse files
authored
Merge pull request #114 from samber/feat-get-map
Get: retrieves the value of a path of *map*
2 parents d02a012 + 6c66e8a commit 15dd68c

File tree

4 files changed

+92
-12
lines changed

4 files changed

+92
-12
lines changed

README.rst

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ Manipulates an iteratee (map, slice) and transforms it to to a flattened collect
343343
funk.Get
344344
........
345345

346-
Retrieves the value at path of struct(s).
346+
Retrieves the value at path of struct(s) or map(s).
347347

348348
.. code-block:: go
349349
@@ -381,6 +381,34 @@ Retrieves the value at path of struct(s).
381381
funk.Get(foo, "Bar.Bars.Bar.Name") // []string{"Level2-1", "Level2-2"}
382382
funk.Get(foo, "Bar.Name") // Test
383383
384+
``funk.Get`` also support ``map`` values:
385+
386+
.. code-block:: go
387+
388+
bar := map[string]interface{}{
389+
"Name": "Test",
390+
}
391+
392+
foo1 := map[string]interface{}{
393+
"ID": 1,
394+
"FirstName": "Dark",
395+
"LastName": "Vador",
396+
"Age": 30,
397+
"Bar": bar,
398+
}
399+
400+
foo2 := &map[string]interface{}{
401+
"ID": 1,
402+
"FirstName": "Dark",
403+
"LastName": "Vador",
404+
"Age": 30,
405+
} // foo2.Bar is nil
406+
407+
funk.Get(bar, "Name") // "Test"
408+
funk.Get([]map[string]interface{}{foo1, foo2}, "Bar.Name") // []string{"Test"}
409+
funk.Get(foo2, "Bar.Name") // nil
410+
411+
384412
``funk.Get`` also handles ``nil`` values:
385413

386414
.. code-block:: go

funk_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,34 @@ var foo2 = &Foo{
7878
LastName: "Vador",
7979
Age: 30,
8080
}
81+
82+
var m1 = map[string]interface{}{
83+
"id": 1,
84+
"firstname": "dark",
85+
"lastname": "vador",
86+
"age": 30,
87+
"bar": map[string]interface{}{
88+
"name": "test",
89+
"bars": []map[string]interface{}{
90+
{
91+
"name": "level1-1",
92+
"bar": map[string]interface{}{
93+
"name": "level2-1",
94+
},
95+
},
96+
{
97+
"name": "level1-2",
98+
"bar": map[string]interface{}{
99+
"name": "level2-2",
100+
},
101+
},
102+
},
103+
},
104+
}
105+
106+
var m2 = map[string]interface{}{
107+
"id": 1,
108+
"firstname": "dark",
109+
"lastname": "vador",
110+
"age": 30,
111+
}

retrieve.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func get(value reflect.Value, path string) reflect.Value {
4747
}
4848

4949
// if the result is a slice of a slice, we need to flatten it
50-
if resultSlice.Type().Elem().Kind() == reflect.Slice {
50+
if resultSlice.Kind() != reflect.Invalid && resultSlice.Type().Elem().Kind() == reflect.Slice {
5151
return flattenDeep(resultSlice)
5252
}
5353

@@ -60,18 +60,17 @@ func get(value reflect.Value, path string) reflect.Value {
6060
value = redirectValue(value)
6161
kind := value.Kind()
6262

63-
if kind == reflect.Invalid {
63+
switch kind {
64+
case reflect.Invalid:
6465
continue
65-
}
66-
67-
if kind == reflect.Struct {
66+
case reflect.Struct:
6867
value = value.FieldByName(part)
69-
continue
70-
}
71-
72-
if kind == reflect.Slice || kind == reflect.Array {
68+
case reflect.Map:
69+
value = value.MapIndex(reflect.ValueOf(part))
70+
case reflect.Slice, reflect.Array:
7371
value = get(value, part)
74-
continue
72+
default:
73+
return reflect.ValueOf(nil)
7574
}
7675
}
7776

retrieve_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,36 @@ func TestGetNil(t *testing.T) {
3535
is.Equal(Get([]*Foo{foo, foo2}, "Bar.Name"), []string{"Test"})
3636
}
3737

38+
func TestGetMap(t *testing.T) {
39+
is := assert.New(t)
40+
m := map[string]interface{}{
41+
"bar": map[string]interface{}{
42+
"name": "foobar",
43+
},
44+
}
45+
46+
is.Equal("foobar", Get(m, "bar.name"))
47+
is.Equal(nil, Get(m, "foo.name"))
48+
is.Equal([]interface{}{"dark", "dark"}, Get([]map[string]interface{}{m1, m2}, "firstname"))
49+
is.Equal([]interface{}{"test"}, Get([]map[string]interface{}{m1, m2}, "bar.name"))
50+
}
51+
3852
func TestGetThroughInterface(t *testing.T) {
3953
is := assert.New(t)
4054

4155
is.Equal(Get(foo, "BarInterface.Bars.Bar.Name"), []string{"Level2-1", "Level2-2"})
4256
is.Equal(Get(foo, "BarPointer.Bars.Bar.Name"), []string{"Level2-1", "Level2-2"})
4357
}
4458

59+
func TestGetNotFound(t *testing.T) {
60+
is := assert.New(t)
61+
62+
is.Equal(nil, Get(foo, "id"))
63+
is.Equal(nil, Get(foo, "id.id"))
64+
is.Equal(nil, Get(foo, "Bar.id"))
65+
is.Equal(nil, Get(foo, "Bars.id"))
66+
}
67+
4568
func TestGetSimple(t *testing.T) {
4669
is := assert.New(t)
4770

@@ -68,5 +91,4 @@ func TestGetOrElse(t *testing.T) {
6891
// test GetOrElse coveers this case
6992
is.Equal("foobar", GetOrElse((*string)(nil), "foobar"))
7093
})
71-
7294
}

0 commit comments

Comments
 (0)