Bladeren bron

Handle error and simple strings in array Scan

Arrays returned by built-in commands do not have error or simple string
members, but arrays returned be scripts and modules can. Update Scan to
handle errors and strings in arrays.
Gary Burd 6 jaren geleden
bovenliggende
commit
e1f5b3308d
2 gewijzigde bestanden met toevoegingen van 60 en 13 verwijderingen
  1. 40 9
      redis/scan.go
  2. 20 4
      redis/scan_test.go

+ 40 - 9
redis/scan.go

@@ -50,31 +50,42 @@ func cannotConvert(d reflect.Value, s interface{}) error {
 	return fmt.Errorf("cannot convert from %s to %s", sname, d.Type())
 }
 
-func convertAssignBulkString(d reflect.Value, s []byte) (err error) {
+func convertAssignError(d reflect.Value, s Error) (err error) {
+	if d.Kind() == reflect.String {
+		d.SetString(string(s))
+	} else if d.Kind() == reflect.Slice && d.Type().Elem().Kind() == reflect.Uint8 {
+		d.SetBytes([]byte(s))
+	} else {
+		err = cannotConvert(d, s)
+	}
+	return
+}
+
+func convertAssignString(d reflect.Value, s string) (err error) {
 	switch d.Type().Kind() {
 	case reflect.Float32, reflect.Float64:
 		var x float64
-		x, err = strconv.ParseFloat(string(s), d.Type().Bits())
+		x, err = strconv.ParseFloat(s, d.Type().Bits())
 		d.SetFloat(x)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		var x int64
-		x, err = strconv.ParseInt(string(s), 10, d.Type().Bits())
+		x, err = strconv.ParseInt(s, 10, d.Type().Bits())
 		d.SetInt(x)
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 		var x uint64
-		x, err = strconv.ParseUint(string(s), 10, d.Type().Bits())
+		x, err = strconv.ParseUint(s, 10, d.Type().Bits())
 		d.SetUint(x)
 	case reflect.Bool:
 		var x bool
-		x, err = strconv.ParseBool(string(s))
+		x, err = strconv.ParseBool(s)
 		d.SetBool(x)
 	case reflect.String:
-		d.SetString(string(s))
+		d.SetString(s)
 	case reflect.Slice:
-		if d.Type().Elem().Kind() != reflect.Uint8 {
-			err = cannotConvert(d, s)
+		if d.Type().Elem().Kind() == reflect.Uint8 {
+			d.SetBytes([]byte(s))
 		} else {
-			d.SetBytes(s)
+			err = cannotConvert(d, s)
 		}
 	default:
 		err = cannotConvert(d, s)
@@ -82,6 +93,22 @@ func convertAssignBulkString(d reflect.Value, s []byte) (err error) {
 	return
 }
 
+func convertAssignBulkString(d reflect.Value, s []byte) (err error) {
+	switch d.Type().Kind() {
+	case reflect.Slice:
+		// Handle []byte destination here to avoid unnecessary
+		// []byte -> string -> []byte converion.
+		if d.Type().Elem().Kind() == reflect.Uint8 {
+			d.SetBytes(s)
+		} else {
+			err = cannotConvert(d, s)
+		}
+	default:
+		err = convertAssignString(d, string(s))
+	}
+	return err
+}
+
 func convertAssignInt(d reflect.Value, s int64) (err error) {
 	switch d.Type().Kind() {
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -134,6 +161,10 @@ func convertAssignValue(d reflect.Value, s interface{}) (err error) {
 		err = convertAssignBulkString(d, s)
 	case int64:
 		err = convertAssignInt(d, s)
+	case string:
+		err = convertAssignString(d, s)
+	case Error:
+		err = convertAssignError(d, s)
 	default:
 		err = cannotConvert(d, s)
 	}

+ 20 - 4
redis/scan_test.go

@@ -72,15 +72,31 @@ var scanConversionTests = []struct {
 	{"hello", "hello"},
 	{[]byte("hello"), "hello"},
 	{[]byte("world"), []byte("world")},
-	{[]interface{}{[]byte("foo")}, []interface{}{[]byte("foo")}},
-	{[]interface{}{[]byte("foo")}, []string{"foo"}},
-	{[]interface{}{[]byte("hello"), []byte("world")}, []string{"hello", "world"}},
-	{[]interface{}{[]byte("bar")}, [][]byte{[]byte("bar")}},
+
+	{[]interface{}{[]byte("b1")}, []interface{}{[]byte("b1")}},
+	{[]interface{}{[]byte("b2")}, []string{"b2"}},
+	{[]interface{}{[]byte("b3"), []byte("b4")}, []string{"b3", "b4"}},
+	{[]interface{}{[]byte("b5")}, [][]byte{[]byte("b5")}},
 	{[]interface{}{[]byte("1")}, []int{1}},
 	{[]interface{}{[]byte("1"), []byte("2")}, []int{1, 2}},
 	{[]interface{}{[]byte("1"), []byte("2")}, []float64{1, 2}},
 	{[]interface{}{[]byte("1")}, []byte{1}},
 	{[]interface{}{[]byte("1")}, []bool{true}},
+
+	{[]interface{}{"s1"}, []interface{}{"s1"}},
+	{[]interface{}{"s2"}, [][]byte{[]byte("s2")}},
+	{[]interface{}{"s3", "s4"}, []string{"s3", "s4"}},
+	{[]interface{}{"s5"}, [][]byte{[]byte("s5")}},
+	{[]interface{}{"1"}, []int{1}},
+	{[]interface{}{"1", "2"}, []int{1, 2}},
+	{[]interface{}{"1", "2"}, []float64{1, 2}},
+	{[]interface{}{"1"}, []byte{1}},
+	{[]interface{}{"1"}, []bool{true}},
+
+	{[]interface{}{redis.Error("e1")}, []interface{}{redis.Error("e1")}},
+	{[]interface{}{redis.Error("e2")}, [][]byte{[]byte("e2")}},
+	{[]interface{}{redis.Error("e3")}, []string{"e3"}},
+
 	{"1m", durationScan{Duration: time.Minute}},
 	{[]byte("1m"), durationScan{Duration: time.Minute}},
 	{time.Minute.Nanoseconds(), durationScan{Duration: time.Minute}},