Repository: gomodule/redigo (go)

Issue:
How to scan struct with nested fields?
This is an example

```go
package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gomodule/redigo/redis"
)

type LiteUser struct {
	LiteUserField int32 `bson:"lite_user_field" json:"lite_user_field" redis:"lite_user_field"`
}

type UserInfo struct {
	UserID      int64       `bson:"_id" json:"_id" redis:"_id"`
	AccountID   int64       `bson:"account_id" json:"account_id" redis:"account_id"`
	GameID      int16       `bson:"game_id" json:"game_id" redis:"game_id"`
	PlayerID    int64       `bson:"player_id" json:"player_id" redis:"player_id"`
	PlayerName  string      `bson:"player_name" json:"player_name" redis:"player_name"`
	PlayerLevel int32       `bson:"player_level" json:"player_level" redis:"player_level"`
	Expire      *time.Timer `bson:"-" json:"-" redis:"-"`

	*LiteUser `bson:"inline" json:",inline" redis:"inline"`
}

var (
	RedisConnectTimeout = time.Second * 2
	RedisReadTimeout    = time.Second * 5
	RedisWriteTimeout   = time.Second * 5
)

func WorkWithRedis() {
	pool := &redis.Pool{
		MaxIdle:   80,
		MaxActive: 12000,
		Dial: func() (redis.Conn, error) {
			c, err := redis.DialTimeout("tcp", "localhost:6379", RedisConnectTimeout, RedisReadTimeout, RedisWriteTimeout)
			if err != nil {
				panic(err.Error())
			}
			return c, err
		},
	}

	u := &UserInfo{
		UserID:     1001,
		PlayerName: "dudu",
		LiteUser: &LiteUser{
			LiteUserField: 2000,
		},
	}

	conn := pool.Get()
	if conn.Err() != nil {
		log.Fatal("redis get connection from pool failed:", conn.Err())
	}

	if _, err := conn.Do("HMSET", redis.Args{}.Add(u.UserID).AddFlat(u)...); err != nil {
		fmt.Println(err)
		return
	}

	v, err := redis.Values(conn.Do("HGETALL", u.UserID))
	if err != nil {
		fmt.Println(err)
		return
	}

	var newUser UserInfo
	if err := redis.ScanStruct(v, &newUser); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("%+v\n", newUser)

}

func main() {

	//WorkWithPool()
	WorkWithRedis()

	// server exit
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
	for {
		sig := <-c
		fmt.Printf("server closing down (signal: %v)", sig)

		switch sig {
		case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
			fmt.Println("server exit safely")
			return
		case syscall.SIGHUP:
		default:
			return
		}
	}
}
```

And this is result of `redis-cli hgetall`
```
➜  test redis-cli hgetall 1001
 1) "_id"
 2) "1001"
 3) "account_id"
 4) "0"
 5) "game_id"
 6) "0"
 7) "player_id"
 8) "0"
 9) "player_name"
10) "dudu"
11) "player_level"
12) "0"
```

The embedded field `lite_user_field` didn't save to redis. Is there any way to make it possible? Thank you.

Pull request description:
feat(AddFlat): Add support for Anonymous field pointers
Add support to AddFlat for Anonymous fields which are pointers.

Fixes #487

Patch:
diff --git a/redis/scan.go b/redis/scan.go
index 289cfd9..4f10066 100644
--- a/redis/scan.go
+++ b/redis/scan.go
@@ -358,10 +358,14 @@ func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *st
 		case f.PkgPath != "" && !f.Anonymous:
 			// Ignore unexported fields.
 		case f.Anonymous:
-			// TODO: Handle pointers. Requires change to decoder and
-			// protection against infinite recursion.
-			if f.Type.Kind() == reflect.Struct {
+			switch f.Type.Kind() {
+			case reflect.Struct:
 				compileStructSpec(f.Type, depth, append(index, i), ss)
+			case reflect.Ptr:
+				// TODO(steve): Protect against infinite recursion.
+				if f.Type.Elem().Kind() == reflect.Struct {
+					compileStructSpec(f.Type.Elem(), depth, append(index, i), ss)
+				}
 			}
 		default:
 			fs := &fieldSpec{name: f.Name}


Test patch:
diff --git a/redis/scan_test.go b/redis/scan_test.go
index 67b1aac..3dd94d5 100644
--- a/redis/scan_test.go
+++ b/redis/scan_test.go
@@ -421,6 +421,14 @@ func ExampleScanSlice() {
 
 var now = time.Now()
 
+type Ed struct {
+	EdI int `redis:"edi"`
+}
+
+type Edp struct {
+	EdpI int `redis:"edpi"`
+}
+
 var argsTests = []struct {
 	title    string
 	actual   redis.Args
@@ -470,6 +478,16 @@ var argsTests = []struct {
 		}),
 		redis.Args{},
 	},
+	{"struct-anonymous",
+		redis.Args{}.AddFlat(struct {
+			Ed
+			*Edp
+		}{
+			Ed{EdI: 2},
+			&Edp{EdpI: 3},
+		}),
+		redis.Args{"edi", 2, "edpi", 3},
+	},
 }
 
 func TestArgs(t *testing.T) {