Skip to content

Commit 6f7651c

Browse files
authored
Merge pull request #2 from theouteredge/master
Added a Generic GetAs[T any] function
2 parents 1de6569 + fa56371 commit 6f7651c

4 files changed

Lines changed: 94 additions & 4 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module github.com/iv-p/mapaccess
22

3-
go 1.13
3+
go 1.18

mapaccess.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@ func Get(data interface{}, key string) (interface{}, error) {
2424
return state, nil
2525
}
2626

27+
// GetAs returns the corresponding key from the map and converts it to type T
28+
func GetAs[T any](data interface{}, key string) (T, error) {
29+
if val, err := Get(data, key); err != nil {
30+
var zero T
31+
return zero, err
32+
33+
} else {
34+
if res, ok := val.(T); ok {
35+
return res, nil
36+
}
37+
var zero T
38+
return zero, fmt.Errorf("expected type %s but got %s", reflect.TypeOf(zero), reflect.TypeOf(val))
39+
}
40+
}
41+
2742
func get(data interface{}, key token) (interface{}, error) {
2843
switch state := data.(type) {
2944
case map[string]interface{}:

mapaccess_test.go

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package mapaccess
33
import (
44
"fmt"
55
"html/template"
6-
"io/ioutil"
6+
"io"
77
"reflect"
88
"testing"
99
)
@@ -69,6 +69,68 @@ func TestGet(t *testing.T) {
6969
}
7070
}
7171

72+
func TestGetAs(t *testing.T) {
73+
type args struct {
74+
key string
75+
data interface{}
76+
}
77+
tests := []struct {
78+
name string
79+
args args
80+
want string
81+
wantErr bool
82+
}{
83+
{"root", args{"one", data}, "two", false},
84+
{"root array", args{"array[0]", data}, "value", false},
85+
{"nested", args{"nested.key", data}, "three", false},
86+
{"nested array", args{"nested.array[0]", data}, "four", false},
87+
88+
{"spaces", args{" one.two[0]", data}, "", true},
89+
{"spaces", args{"o.test.", data}, "", true},
90+
{"spaces", args{"[0]", data}, "", true},
91+
}
92+
for _, tt := range tests {
93+
t.Run(tt.name, func(t *testing.T) {
94+
got, err := GetAs[string](tt.args.data, tt.args.key)
95+
if (err != nil) != tt.wantErr {
96+
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
97+
return
98+
}
99+
if got != tt.want {
100+
t.Errorf("Get() = %v, want %v", got, tt.want)
101+
}
102+
})
103+
}
104+
}
105+
106+
func TestGetAsInt(t *testing.T) {
107+
m := map[string]interface{}{
108+
"one": 1,
109+
"two": 2.2,
110+
"three": 0.3,
111+
}
112+
113+
if val, err := GetAs[int](m, "one"); err != nil {
114+
t.Errorf("GetAs() error = %v", err)
115+
116+
} else if val != 1 {
117+
t.Errorf("GetAs() = %v, want %v", val, 1)
118+
}
119+
120+
if val, err := GetAs[float64](m, "two"); err != nil {
121+
t.Errorf("GetAs() error = %v", err)
122+
} else if val != 2.2 {
123+
t.Errorf("GetAs() = %v, want %v", val, 2.2)
124+
}
125+
126+
if val, err := GetAs[float64](m, "three"); err != nil {
127+
t.Errorf("GetAs() error = %v", err)
128+
} else if val != 0.3 {
129+
t.Errorf("GetAs() = %v, want %v", val, 0.3)
130+
}
131+
132+
}
133+
72134
func benchmarkMapaccess(key string, b *testing.B) {
73135
for n := 0; n < b.N; n++ {
74136
Get(data, key)
@@ -81,7 +143,7 @@ func benchmarkGoTemplate(key string, b *testing.B) {
81143
if err != nil {
82144
fmt.Println(err)
83145
}
84-
t.Execute(ioutil.Discard, typed)
146+
t.Execute(io.Discard, typed)
85147
}
86148
}
87149

readme.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ It is intended towards using with serializing arbitary JSON and getting an arbit
2828
j := []byte(`{
2929
"id": "9b92b11b-b57f-4fa6-af5e-e35a290dc764",
3030
"name": "John Doe",
31+
"age": 44,
3132
"friends": [
3233
{
33-
"name": "Jaime Mckinney"
34+
"name": "Jaime Mckinney",
35+
"age": 41
3436
},
3537
{
3638
"name": "Evangeline Alvarado"
@@ -89,6 +91,17 @@ mapaccess.Get(data, "[0].[1]")
8991
mapaccess.Get(data, "friends[0].[1]")
9092
```
9193

94+
### Generic GetAs[T any] Method
95+
The `GetAs[T any]` method allows you too simplify accessing maps by casting the extraced value to a concrete type
96+
```go
97+
// Valid
98+
mapaccess.GetAs[string](data, "id")
99+
mapaccess.GetAs[string](data, "name")
100+
mapaccess.GetAs[int](data, "age")
101+
mapaccess.GetAs[string](data, "friends[0].name")
102+
mapaccess.GetAs[int](data, "friends[0].age")
103+
```
104+
92105
## Valid keys
93106

94107
There is a limitation of the alphabet for keys, it includes underscores, dashes and alphanumeric characters.

0 commit comments

Comments
 (0)