...

Source file src/github.com/gomodule/redigo/redis/reply.go

Documentation: github.com/gomodule/redigo/redis

     1  // Copyright 2012 Gary Burd
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package redis
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"strconv"
    21  )
    22  
    23  // ErrNil indicates that a reply value is nil.
    24  var ErrNil = errors.New("redigo: nil returned")
    25  
    26  // Int is a helper that converts a command reply to an integer. If err is not
    27  // equal to nil, then Int returns 0, err. Otherwise, Int converts the
    28  // reply to an int as follows:
    29  //
    30  //  Reply type    Result
    31  //  integer       int(reply), nil
    32  //  bulk string   parsed reply, nil
    33  //  nil           0, ErrNil
    34  //  other         0, error
    35  func Int(reply interface{}, err error) (int, error) {
    36  	if err != nil {
    37  		return 0, err
    38  	}
    39  	switch reply := reply.(type) {
    40  	case int64:
    41  		x := int(reply)
    42  		if int64(x) != reply {
    43  			return 0, strconv.ErrRange
    44  		}
    45  		return x, nil
    46  	case []byte:
    47  		n, err := strconv.ParseInt(string(reply), 10, 0)
    48  		return int(n), err
    49  	case nil:
    50  		return 0, ErrNil
    51  	case Error:
    52  		return 0, reply
    53  	}
    54  	return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", reply)
    55  }
    56  
    57  // Int64 is a helper that converts a command reply to 64 bit integer. If err is
    58  // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
    59  // reply to an int64 as follows:
    60  //
    61  //  Reply type    Result
    62  //  integer       reply, nil
    63  //  bulk string   parsed reply, nil
    64  //  nil           0, ErrNil
    65  //  other         0, error
    66  func Int64(reply interface{}, err error) (int64, error) {
    67  	if err != nil {
    68  		return 0, err
    69  	}
    70  	switch reply := reply.(type) {
    71  	case int64:
    72  		return reply, nil
    73  	case []byte:
    74  		n, err := strconv.ParseInt(string(reply), 10, 64)
    75  		return n, err
    76  	case nil:
    77  		return 0, ErrNil
    78  	case Error:
    79  		return 0, reply
    80  	}
    81  	return 0, fmt.Errorf("redigo: unexpected type for Int64, got type %T", reply)
    82  }
    83  
    84  var errNegativeInt = errors.New("redigo: unexpected value for Uint64")
    85  
    86  // Uint64 is a helper that converts a command reply to 64 bit integer. If err is
    87  // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
    88  // reply to an int64 as follows:
    89  //
    90  //  Reply type    Result
    91  //  integer       reply, nil
    92  //  bulk string   parsed reply, nil
    93  //  nil           0, ErrNil
    94  //  other         0, error
    95  func Uint64(reply interface{}, err error) (uint64, error) {
    96  	if err != nil {
    97  		return 0, err
    98  	}
    99  	switch reply := reply.(type) {
   100  	case int64:
   101  		if reply < 0 {
   102  			return 0, errNegativeInt
   103  		}
   104  		return uint64(reply), nil
   105  	case []byte:
   106  		n, err := strconv.ParseUint(string(reply), 10, 64)
   107  		return n, err
   108  	case nil:
   109  		return 0, ErrNil
   110  	case Error:
   111  		return 0, reply
   112  	}
   113  	return 0, fmt.Errorf("redigo: unexpected type for Uint64, got type %T", reply)
   114  }
   115  
   116  // Float64 is a helper that converts a command reply to 64 bit float. If err is
   117  // not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts
   118  // the reply to an int as follows:
   119  //
   120  //  Reply type    Result
   121  //  bulk string   parsed reply, nil
   122  //  nil           0, ErrNil
   123  //  other         0, error
   124  func Float64(reply interface{}, err error) (float64, error) {
   125  	if err != nil {
   126  		return 0, err
   127  	}
   128  	switch reply := reply.(type) {
   129  	case []byte:
   130  		n, err := strconv.ParseFloat(string(reply), 64)
   131  		return n, err
   132  	case nil:
   133  		return 0, ErrNil
   134  	case Error:
   135  		return 0, reply
   136  	}
   137  	return 0, fmt.Errorf("redigo: unexpected type for Float64, got type %T", reply)
   138  }
   139  
   140  // String is a helper that converts a command reply to a string. If err is not
   141  // equal to nil, then String returns "", err. Otherwise String converts the
   142  // reply to a string as follows:
   143  //
   144  //  Reply type      Result
   145  //  bulk string     string(reply), nil
   146  //  simple string   reply, nil
   147  //  nil             "",  ErrNil
   148  //  other           "",  error
   149  func String(reply interface{}, err error) (string, error) {
   150  	if err != nil {
   151  		return "", err
   152  	}
   153  	switch reply := reply.(type) {
   154  	case []byte:
   155  		return string(reply), nil
   156  	case string:
   157  		return reply, nil
   158  	case nil:
   159  		return "", ErrNil
   160  	case Error:
   161  		return "", reply
   162  	}
   163  	return "", fmt.Errorf("redigo: unexpected type for String, got type %T", reply)
   164  }
   165  
   166  // Bytes is a helper that converts a command reply to a slice of bytes. If err
   167  // is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts
   168  // the reply to a slice of bytes as follows:
   169  //
   170  //  Reply type      Result
   171  //  bulk string     reply, nil
   172  //  simple string   []byte(reply), nil
   173  //  nil             nil, ErrNil
   174  //  other           nil, error
   175  func Bytes(reply interface{}, err error) ([]byte, error) {
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	switch reply := reply.(type) {
   180  	case []byte:
   181  		return reply, nil
   182  	case string:
   183  		return []byte(reply), nil
   184  	case nil:
   185  		return nil, ErrNil
   186  	case Error:
   187  		return nil, reply
   188  	}
   189  	return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply)
   190  }
   191  
   192  // Bool is a helper that converts a command reply to a boolean. If err is not
   193  // equal to nil, then Bool returns false, err. Otherwise Bool converts the
   194  // reply to boolean as follows:
   195  //
   196  //  Reply type      Result
   197  //  integer         value != 0, nil
   198  //  bulk string     strconv.ParseBool(reply)
   199  //  nil             false, ErrNil
   200  //  other           false, error
   201  func Bool(reply interface{}, err error) (bool, error) {
   202  	if err != nil {
   203  		return false, err
   204  	}
   205  	switch reply := reply.(type) {
   206  	case int64:
   207  		return reply != 0, nil
   208  	case []byte:
   209  		return strconv.ParseBool(string(reply))
   210  	case nil:
   211  		return false, ErrNil
   212  	case Error:
   213  		return false, reply
   214  	}
   215  	return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply)
   216  }
   217  
   218  // MultiBulk is a helper that converts an array command reply to a []interface{}.
   219  //
   220  // Deprecated: Use Values instead.
   221  func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) }
   222  
   223  // Values is a helper that converts an array command reply to a []interface{}.
   224  // If err is not equal to nil, then Values returns nil, err. Otherwise, Values
   225  // converts the reply as follows:
   226  //
   227  //  Reply type      Result
   228  //  array           reply, nil
   229  //  nil             nil, ErrNil
   230  //  other           nil, error
   231  func Values(reply interface{}, err error) ([]interface{}, error) {
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	switch reply := reply.(type) {
   236  	case []interface{}:
   237  		return reply, nil
   238  	case nil:
   239  		return nil, ErrNil
   240  	case Error:
   241  		return nil, reply
   242  	}
   243  	return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply)
   244  }
   245  
   246  func sliceHelper(reply interface{}, err error, name string, makeSlice func(int), assign func(int, interface{}) error) error {
   247  	if err != nil {
   248  		return err
   249  	}
   250  	switch reply := reply.(type) {
   251  	case []interface{}:
   252  		makeSlice(len(reply))
   253  		for i := range reply {
   254  			if reply[i] == nil {
   255  				continue
   256  			}
   257  			if err := assign(i, reply[i]); err != nil {
   258  				return err
   259  			}
   260  		}
   261  		return nil
   262  	case nil:
   263  		return ErrNil
   264  	case Error:
   265  		return reply
   266  	}
   267  	return fmt.Errorf("redigo: unexpected type for %s, got type %T", name, reply)
   268  }
   269  
   270  // Float64s is a helper that converts an array command reply to a []float64. If
   271  // err is not equal to nil, then Float64s returns nil, err. Nil array items are
   272  // converted to 0 in the output slice. Floats64 returns an error if an array
   273  // item is not a bulk string or nil.
   274  func Float64s(reply interface{}, err error) ([]float64, error) {
   275  	var result []float64
   276  	err = sliceHelper(reply, err, "Float64s", func(n int) { result = make([]float64, n) }, func(i int, v interface{}) error {
   277  		p, ok := v.([]byte)
   278  		if !ok {
   279  			return fmt.Errorf("redigo: unexpected element type for Floats64, got type %T", v)
   280  		}
   281  		f, err := strconv.ParseFloat(string(p), 64)
   282  		result[i] = f
   283  		return err
   284  	})
   285  	return result, err
   286  }
   287  
   288  // Strings is a helper that converts an array command reply to a []string. If
   289  // err is not equal to nil, then Strings returns nil, err. Nil array items are
   290  // converted to "" in the output slice. Strings returns an error if an array
   291  // item is not a bulk string or nil.
   292  func Strings(reply interface{}, err error) ([]string, error) {
   293  	var result []string
   294  	err = sliceHelper(reply, err, "Strings", func(n int) { result = make([]string, n) }, func(i int, v interface{}) error {
   295  		switch v := v.(type) {
   296  		case string:
   297  			result[i] = v
   298  			return nil
   299  		case []byte:
   300  			result[i] = string(v)
   301  			return nil
   302  		default:
   303  			return fmt.Errorf("redigo: unexpected element type for Strings, got type %T", v)
   304  		}
   305  	})
   306  	return result, err
   307  }
   308  
   309  // ByteSlices is a helper that converts an array command reply to a [][]byte.
   310  // If err is not equal to nil, then ByteSlices returns nil, err. Nil array
   311  // items are stay nil. ByteSlices returns an error if an array item is not a
   312  // bulk string or nil.
   313  func ByteSlices(reply interface{}, err error) ([][]byte, error) {
   314  	var result [][]byte
   315  	err = sliceHelper(reply, err, "ByteSlices", func(n int) { result = make([][]byte, n) }, func(i int, v interface{}) error {
   316  		p, ok := v.([]byte)
   317  		if !ok {
   318  			return fmt.Errorf("redigo: unexpected element type for ByteSlices, got type %T", v)
   319  		}
   320  		result[i] = p
   321  		return nil
   322  	})
   323  	return result, err
   324  }
   325  
   326  // Int64s is a helper that converts an array command reply to a []int64.
   327  // If err is not equal to nil, then Int64s returns nil, err. Nil array
   328  // items are stay nil. Int64s returns an error if an array item is not a
   329  // bulk string or nil.
   330  func Int64s(reply interface{}, err error) ([]int64, error) {
   331  	var result []int64
   332  	err = sliceHelper(reply, err, "Int64s", func(n int) { result = make([]int64, n) }, func(i int, v interface{}) error {
   333  		switch v := v.(type) {
   334  		case int64:
   335  			result[i] = v
   336  			return nil
   337  		case []byte:
   338  			n, err := strconv.ParseInt(string(v), 10, 64)
   339  			result[i] = n
   340  			return err
   341  		default:
   342  			return fmt.Errorf("redigo: unexpected element type for Int64s, got type %T", v)
   343  		}
   344  	})
   345  	return result, err
   346  }
   347  
   348  // Ints is a helper that converts an array command reply to a []in.
   349  // If err is not equal to nil, then Ints returns nil, err. Nil array
   350  // items are stay nil. Ints returns an error if an array item is not a
   351  // bulk string or nil.
   352  func Ints(reply interface{}, err error) ([]int, error) {
   353  	var result []int
   354  	err = sliceHelper(reply, err, "Ints", func(n int) { result = make([]int, n) }, func(i int, v interface{}) error {
   355  		switch v := v.(type) {
   356  		case int64:
   357  			n := int(v)
   358  			if int64(n) != v {
   359  				return strconv.ErrRange
   360  			}
   361  			result[i] = n
   362  			return nil
   363  		case []byte:
   364  			n, err := strconv.Atoi(string(v))
   365  			result[i] = n
   366  			return err
   367  		default:
   368  			return fmt.Errorf("redigo: unexpected element type for Ints, got type %T", v)
   369  		}
   370  	})
   371  	return result, err
   372  }
   373  
   374  // StringMap is a helper that converts an array of strings (alternating key, value)
   375  // into a map[string]string. The HGETALL and CONFIG GET commands return replies in this format.
   376  // Requires an even number of values in result.
   377  func StringMap(result interface{}, err error) (map[string]string, error) {
   378  	values, err := Values(result, err)
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  	if len(values)%2 != 0 {
   383  		return nil, errors.New("redigo: StringMap expects even number of values result")
   384  	}
   385  	m := make(map[string]string, len(values)/2)
   386  	for i := 0; i < len(values); i += 2 {
   387  		key, okKey := values[i].([]byte)
   388  		value, okValue := values[i+1].([]byte)
   389  		if !okKey || !okValue {
   390  			return nil, errors.New("redigo: StringMap key not a bulk string value")
   391  		}
   392  		m[string(key)] = string(value)
   393  	}
   394  	return m, nil
   395  }
   396  
   397  // IntMap is a helper that converts an array of strings (alternating key, value)
   398  // into a map[string]int. The HGETALL commands return replies in this format.
   399  // Requires an even number of values in result.
   400  func IntMap(result interface{}, err error) (map[string]int, error) {
   401  	values, err := Values(result, err)
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  	if len(values)%2 != 0 {
   406  		return nil, errors.New("redigo: IntMap expects even number of values result")
   407  	}
   408  	m := make(map[string]int, len(values)/2)
   409  	for i := 0; i < len(values); i += 2 {
   410  		key, ok := values[i].([]byte)
   411  		if !ok {
   412  			return nil, errors.New("redigo: IntMap key not a bulk string value")
   413  		}
   414  		value, err := Int(values[i+1], nil)
   415  		if err != nil {
   416  			return nil, err
   417  		}
   418  		m[string(key)] = value
   419  	}
   420  	return m, nil
   421  }
   422  
   423  // Int64Map is a helper that converts an array of strings (alternating key, value)
   424  // into a map[string]int64. The HGETALL commands return replies in this format.
   425  // Requires an even number of values in result.
   426  func Int64Map(result interface{}, err error) (map[string]int64, error) {
   427  	values, err := Values(result, err)
   428  	if err != nil {
   429  		return nil, err
   430  	}
   431  	if len(values)%2 != 0 {
   432  		return nil, errors.New("redigo: Int64Map expects even number of values result")
   433  	}
   434  	m := make(map[string]int64, len(values)/2)
   435  	for i := 0; i < len(values); i += 2 {
   436  		key, ok := values[i].([]byte)
   437  		if !ok {
   438  			return nil, errors.New("redigo: Int64Map key not a bulk string value")
   439  		}
   440  		value, err := Int64(values[i+1], nil)
   441  		if err != nil {
   442  			return nil, err
   443  		}
   444  		m[string(key)] = value
   445  	}
   446  	return m, nil
   447  }
   448  
   449  // Positions is a helper that converts an array of positions (lat, long)
   450  // into a [][2]float64. The GEOPOS command returns replies in this format.
   451  func Positions(result interface{}, err error) ([]*[2]float64, error) {
   452  	values, err := Values(result, err)
   453  	if err != nil {
   454  		return nil, err
   455  	}
   456  	positions := make([]*[2]float64, len(values))
   457  	for i := range values {
   458  		if values[i] == nil {
   459  			continue
   460  		}
   461  		p, ok := values[i].([]interface{})
   462  		if !ok {
   463  			return nil, fmt.Errorf("redigo: unexpected element type for interface slice, got type %T", values[i])
   464  		}
   465  		if len(p) != 2 {
   466  			return nil, fmt.Errorf("redigo: unexpected number of values for a member position, got %d", len(p))
   467  		}
   468  		lat, err := Float64(p[0], nil)
   469  		if err != nil {
   470  			return nil, err
   471  		}
   472  		long, err := Float64(p[1], nil)
   473  		if err != nil {
   474  			return nil, err
   475  		}
   476  		positions[i] = &[2]float64{lat, long}
   477  	}
   478  	return positions, nil
   479  }
   480  

View as plain text