Repository: gomodule/redigo
Pull request #474 (2020-05-01 15:28:49)

fix: Argument processing on pointers
Fix Argument interface processing on struct pointer types which was broken by #428 and not quite corrected by #446.

stevenh: @cyx and @wych42 could you review / test this change in your setup as it could well impacts you both.
wych42: It looks good to me, and does not break my current setup&usage.

Patch:
diff --git a/go.sum b/go.sum
index 5b5dd18..331fa69 100644
--- a/go.sum
+++ b/go.sum
@@ -7,4 +7,5 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/redis/scan.go b/redis/scan.go
index 10c1d26..289cfd9 100644
--- a/redis/scan.go
+++ b/redis/scan.go
@@ -646,16 +646,14 @@ func flattenStruct(args Args, v reflect.Value) Args {
 				continue
 			}
 		}
-		if fv.Kind() == reflect.Ptr {
+		if arg, ok := fv.Interface().(Argument); ok {
+			args = append(args, fs.name, arg.RedisArg())
+		} else if fv.Kind() == reflect.Ptr {
 			if !fv.IsNil() {
 				args = append(args, fs.name, fv.Elem().Interface())
 			}
 		} else {
-			if arg, ok := fv.Interface().(Argument); ok {
-				args = append(args, fs.name, arg.RedisArg())
-			} else {
-				args = append(args, fs.name, fv.Interface())
-			}
+			args = append(args, fs.name, fv.Interface())
 		}
 	}
 	return args


Test patch:
diff --git a/redis/scan_test.go b/redis/scan_test.go
index 8d06b3c..67b1aac 100644
--- a/redis/scan_test.go
+++ b/redis/scan_test.go
@@ -419,12 +419,14 @@ func ExampleScanSlice() {
 	// [{Earthbound 1} {Beat 4} {Red 5}]
 }
 
+var now = time.Now()
+
 var argsTests = []struct {
 	title    string
 	actual   redis.Args
 	expected redis.Args
 }{
-	{"struct ptr",
+	{"struct-ptr",
 		redis.Args{}.AddFlat(&struct {
 			I    int               `redis:"i"`
 			U    uint              `redis:"u"`
@@ -444,15 +446,23 @@ var argsTests = []struct {
 		redis.Args{}.AddFlat(struct{ I int }{123}),
 		redis.Args{"I", 123},
 	},
-	{"struct with RedisArg",
+	{"struct-with-RedisArg-direct",
 		redis.Args{}.AddFlat(struct{ T CustomTime }{CustomTime{Time: time.Unix(1573231058, 0)}}),
 		redis.Args{"T", int64(1573231058)},
 	},
+	{"struct-with-RedisArg-direct-ptr",
+		redis.Args{}.AddFlat(struct{ T *CustomTime }{&CustomTime{Time: time.Unix(1573231058, 0)}}),
+		redis.Args{"T", int64(1573231058)},
+	},
+	{"struct-with-RedisArg-ptr",
+		redis.Args{}.AddFlat(struct{ T *CustomTimePtr }{&CustomTimePtr{Time: time.Unix(1573231058, 0)}}),
+		redis.Args{"T", int64(1573231058)},
+	},
 	{"slice",
 		redis.Args{}.Add(1).AddFlat([]string{"a", "b", "c"}).Add(2),
 		redis.Args{1, "a", "b", "c", 2},
 	},
-	{"struct omitempty",
+	{"struct-omitempty",
 		redis.Args{}.AddFlat(&struct {
 			Sdp *durationArg `redis:"Sdp,omitempty"`
 		}{
@@ -464,12 +474,22 @@ var argsTests = []struct {
 
 func TestArgs(t *testing.T) {
 	for _, tt := range argsTests {
-		if !reflect.DeepEqual(tt.actual, tt.expected) {
-			t.Fatalf("%s is %v, want %v", tt.title, tt.actual, tt.expected)
-		}
+		t.Run(tt.title, func(t *testing.T) {
+			if !reflect.DeepEqual(tt.actual, tt.expected) {
+				t.Fatalf("is %v, want %v", tt.actual, tt.expected)
+			}
+		})
 	}
 }
 
+type CustomTimePtr struct {
+	time.Time
+}
+
+func (t *CustomTimePtr) RedisArg() interface{} {
+	return t.Unix()
+}
+
 type CustomTime struct {
 	time.Time
 }