Skip to content

Commit

Permalink
Merge pull request #114 from samber/feat-get-map
Browse files Browse the repository at this point in the history
Get: retrieves the value of a path of *map*
  • Loading branch information
thoas authored Mar 11, 2021
2 parents d02a012 + 6c66e8a commit 15dd68c
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 12 deletions.
30 changes: 29 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ Manipulates an iteratee (map, slice) and transforms it to to a flattened collect
funk.Get
........

Retrieves the value at path of struct(s).
Retrieves the value at path of struct(s) or map(s).

.. code-block:: go
Expand Down Expand Up @@ -381,6 +381,34 @@ Retrieves the value at path of struct(s).
funk.Get(foo, "Bar.Bars.Bar.Name") // []string{"Level2-1", "Level2-2"}
funk.Get(foo, "Bar.Name") // Test
``funk.Get`` also support ``map`` values:

.. code-block:: go
bar := map[string]interface{}{
"Name": "Test",
}
foo1 := map[string]interface{}{
"ID": 1,
"FirstName": "Dark",
"LastName": "Vador",
"Age": 30,
"Bar": bar,
}
foo2 := &map[string]interface{}{
"ID": 1,
"FirstName": "Dark",
"LastName": "Vador",
"Age": 30,
} // foo2.Bar is nil
funk.Get(bar, "Name") // "Test"
funk.Get([]map[string]interface{}{foo1, foo2}, "Bar.Name") // []string{"Test"}
funk.Get(foo2, "Bar.Name") // nil
``funk.Get`` also handles ``nil`` values:

.. code-block:: go
Expand Down
31 changes: 31 additions & 0 deletions funk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,34 @@ var foo2 = &Foo{
LastName: "Vador",
Age: 30,
}

var m1 = map[string]interface{}{
"id": 1,
"firstname": "dark",
"lastname": "vador",
"age": 30,
"bar": map[string]interface{}{
"name": "test",
"bars": []map[string]interface{}{
{
"name": "level1-1",
"bar": map[string]interface{}{
"name": "level2-1",
},
},
{
"name": "level1-2",
"bar": map[string]interface{}{
"name": "level2-2",
},
},
},
},
}

var m2 = map[string]interface{}{
"id": 1,
"firstname": "dark",
"lastname": "vador",
"age": 30,
}
19 changes: 9 additions & 10 deletions retrieve.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func get(value reflect.Value, path string) reflect.Value {
}

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

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

if kind == reflect.Invalid {
switch kind {
case reflect.Invalid:
continue
}

if kind == reflect.Struct {
case reflect.Struct:
value = value.FieldByName(part)
continue
}

if kind == reflect.Slice || kind == reflect.Array {
case reflect.Map:
value = value.MapIndex(reflect.ValueOf(part))
case reflect.Slice, reflect.Array:
value = get(value, part)
continue
default:
return reflect.ValueOf(nil)
}
}

Expand Down
24 changes: 23 additions & 1 deletion retrieve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,36 @@ func TestGetNil(t *testing.T) {
is.Equal(Get([]*Foo{foo, foo2}, "Bar.Name"), []string{"Test"})
}

func TestGetMap(t *testing.T) {
is := assert.New(t)
m := map[string]interface{}{
"bar": map[string]interface{}{
"name": "foobar",
},
}

is.Equal("foobar", Get(m, "bar.name"))
is.Equal(nil, Get(m, "foo.name"))
is.Equal([]interface{}{"dark", "dark"}, Get([]map[string]interface{}{m1, m2}, "firstname"))
is.Equal([]interface{}{"test"}, Get([]map[string]interface{}{m1, m2}, "bar.name"))
}

func TestGetThroughInterface(t *testing.T) {
is := assert.New(t)

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

func TestGetNotFound(t *testing.T) {
is := assert.New(t)

is.Equal(nil, Get(foo, "id"))
is.Equal(nil, Get(foo, "id.id"))
is.Equal(nil, Get(foo, "Bar.id"))
is.Equal(nil, Get(foo, "Bars.id"))
}

func TestGetSimple(t *testing.T) {
is := assert.New(t)

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

}

0 comments on commit 15dd68c

Please sign in to comment.