...

Source file src/github.com/gomodule/redigo/redis/scan.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  	"reflect"
    21  	"strconv"
    22  	"strings"
    23  	"sync"
    24  )
    25  
    26  func ensureLen(d reflect.Value, n int) {
    27  	if n > d.Cap() {
    28  		d.Set(reflect.MakeSlice(d.Type(), n, n))
    29  	} else {
    30  		d.SetLen(n)
    31  	}
    32  }
    33  
    34  func cannotConvert(d reflect.Value, s interface{}) error {
    35  	var sname string
    36  	switch s.(type) {
    37  	case string:
    38  		sname = "Redis simple string"
    39  	case Error:
    40  		sname = "Redis error"
    41  	case int64:
    42  		sname = "Redis integer"
    43  	case []byte:
    44  		sname = "Redis bulk string"
    45  	case []interface{}:
    46  		sname = "Redis array"
    47  	default:
    48  		sname = reflect.TypeOf(s).String()
    49  	}
    50  	return fmt.Errorf("cannot convert from %s to %s", sname, d.Type())
    51  }
    52  
    53  func convertAssignBulkString(d reflect.Value, s []byte) (err error) {
    54  	switch d.Type().Kind() {
    55  	case reflect.Float32, reflect.Float64:
    56  		var x float64
    57  		x, err = strconv.ParseFloat(string(s), d.Type().Bits())
    58  		d.SetFloat(x)
    59  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    60  		var x int64
    61  		x, err = strconv.ParseInt(string(s), 10, d.Type().Bits())
    62  		d.SetInt(x)
    63  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    64  		var x uint64
    65  		x, err = strconv.ParseUint(string(s), 10, d.Type().Bits())
    66  		d.SetUint(x)
    67  	case reflect.Bool:
    68  		var x bool
    69  		x, err = strconv.ParseBool(string(s))
    70  		d.SetBool(x)
    71  	case reflect.String:
    72  		d.SetString(string(s))
    73  	case reflect.Slice:
    74  		if d.Type().Elem().Kind() != reflect.Uint8 {
    75  			err = cannotConvert(d, s)
    76  		} else {
    77  			d.SetBytes(s)
    78  		}
    79  	default:
    80  		err = cannotConvert(d, s)
    81  	}
    82  	return
    83  }
    84  
    85  func convertAssignInt(d reflect.Value, s int64) (err error) {
    86  	switch d.Type().Kind() {
    87  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    88  		d.SetInt(s)
    89  		if d.Int() != s {
    90  			err = strconv.ErrRange
    91  			d.SetInt(0)
    92  		}
    93  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    94  		if s < 0 {
    95  			err = strconv.ErrRange
    96  		} else {
    97  			x := uint64(s)
    98  			d.SetUint(x)
    99  			if d.Uint() != x {
   100  				err = strconv.ErrRange
   101  				d.SetUint(0)
   102  			}
   103  		}
   104  	case reflect.Bool:
   105  		d.SetBool(s != 0)
   106  	default:
   107  		err = cannotConvert(d, s)
   108  	}
   109  	return
   110  }
   111  
   112  func convertAssignValue(d reflect.Value, s interface{}) (err error) {
   113  	if d.Kind() != reflect.Ptr {
   114  		if d.CanAddr() {
   115  			d2 := d.Addr()
   116  			if d2.CanInterface() {
   117  				if scanner, ok := d2.Interface().(Scanner); ok {
   118  					return scanner.RedisScan(s)
   119  				}
   120  			}
   121  		}
   122  	} else if d.CanInterface() {
   123  		// Already a reflect.Ptr
   124  		if d.IsNil() {
   125  			d.Set(reflect.New(d.Type().Elem()))
   126  		}
   127  		if scanner, ok := d.Interface().(Scanner); ok {
   128  			return scanner.RedisScan(s)
   129  		}
   130  	}
   131  
   132  	switch s := s.(type) {
   133  	case []byte:
   134  		err = convertAssignBulkString(d, s)
   135  	case int64:
   136  		err = convertAssignInt(d, s)
   137  	default:
   138  		err = cannotConvert(d, s)
   139  	}
   140  	return err
   141  }
   142  
   143  func convertAssignArray(d reflect.Value, s []interface{}) error {
   144  	if d.Type().Kind() != reflect.Slice {
   145  		return cannotConvert(d, s)
   146  	}
   147  	ensureLen(d, len(s))
   148  	for i := 0; i < len(s); i++ {
   149  		if err := convertAssignValue(d.Index(i), s[i]); err != nil {
   150  			return err
   151  		}
   152  	}
   153  	return nil
   154  }
   155  
   156  func convertAssign(d interface{}, s interface{}) (err error) {
   157  	if scanner, ok := d.(Scanner); ok {
   158  		return scanner.RedisScan(s)
   159  	}
   160  
   161  	// Handle the most common destination types using type switches and
   162  	// fall back to reflection for all other types.
   163  	switch s := s.(type) {
   164  	case nil:
   165  		// ignore
   166  	case []byte:
   167  		switch d := d.(type) {
   168  		case *string:
   169  			*d = string(s)
   170  		case *int:
   171  			*d, err = strconv.Atoi(string(s))
   172  		case *bool:
   173  			*d, err = strconv.ParseBool(string(s))
   174  		case *[]byte:
   175  			*d = s
   176  		case *interface{}:
   177  			*d = s
   178  		case nil:
   179  			// skip value
   180  		default:
   181  			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
   182  				err = cannotConvert(d, s)
   183  			} else {
   184  				err = convertAssignBulkString(d.Elem(), s)
   185  			}
   186  		}
   187  	case int64:
   188  		switch d := d.(type) {
   189  		case *int:
   190  			x := int(s)
   191  			if int64(x) != s {
   192  				err = strconv.ErrRange
   193  				x = 0
   194  			}
   195  			*d = x
   196  		case *bool:
   197  			*d = s != 0
   198  		case *interface{}:
   199  			*d = s
   200  		case nil:
   201  			// skip value
   202  		default:
   203  			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
   204  				err = cannotConvert(d, s)
   205  			} else {
   206  				err = convertAssignInt(d.Elem(), s)
   207  			}
   208  		}
   209  	case string:
   210  		switch d := d.(type) {
   211  		case *string:
   212  			*d = s
   213  		case *interface{}:
   214  			*d = s
   215  		case nil:
   216  			// skip value
   217  		default:
   218  			err = cannotConvert(reflect.ValueOf(d), s)
   219  		}
   220  	case []interface{}:
   221  		switch d := d.(type) {
   222  		case *[]interface{}:
   223  			*d = s
   224  		case *interface{}:
   225  			*d = s
   226  		case nil:
   227  			// skip value
   228  		default:
   229  			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
   230  				err = cannotConvert(d, s)
   231  			} else {
   232  				err = convertAssignArray(d.Elem(), s)
   233  			}
   234  		}
   235  	case Error:
   236  		err = s
   237  	default:
   238  		err = cannotConvert(reflect.ValueOf(d), s)
   239  	}
   240  	return
   241  }
   242  
   243  // Scan copies from src to the values pointed at by dest.
   244  //
   245  // Scan uses RedisScan if available otherwise:
   246  //
   247  // The values pointed at by dest must be an integer, float, boolean, string,
   248  // []byte, interface{} or slices of these types. Scan uses the standard strconv
   249  // package to convert bulk strings to numeric and boolean types.
   250  //
   251  // If a dest value is nil, then the corresponding src value is skipped.
   252  //
   253  // If a src element is nil, then the corresponding dest value is not modified.
   254  //
   255  // To enable easy use of Scan in a loop, Scan returns the slice of src
   256  // following the copied values.
   257  func Scan(src []interface{}, dest ...interface{}) ([]interface{}, error) {
   258  	if len(src) < len(dest) {
   259  		return nil, errors.New("redigo.Scan: array short")
   260  	}
   261  	var err error
   262  	for i, d := range dest {
   263  		err = convertAssign(d, src[i])
   264  		if err != nil {
   265  			err = fmt.Errorf("redigo.Scan: cannot assign to dest %d: %v", i, err)
   266  			break
   267  		}
   268  	}
   269  	return src[len(dest):], err
   270  }
   271  
   272  type fieldSpec struct {
   273  	name      string
   274  	index     []int
   275  	omitEmpty bool
   276  }
   277  
   278  type structSpec struct {
   279  	m map[string]*fieldSpec
   280  	l []*fieldSpec
   281  }
   282  
   283  func (ss *structSpec) fieldSpec(name []byte) *fieldSpec {
   284  	return ss.m[string(name)]
   285  }
   286  
   287  func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *structSpec) {
   288  	for i := 0; i < t.NumField(); i++ {
   289  		f := t.Field(i)
   290  		switch {
   291  		case f.PkgPath != "" && !f.Anonymous:
   292  			// Ignore unexported fields.
   293  		case f.Anonymous:
   294  			// TODO: Handle pointers. Requires change to decoder and
   295  			// protection against infinite recursion.
   296  			if f.Type.Kind() == reflect.Struct {
   297  				compileStructSpec(f.Type, depth, append(index, i), ss)
   298  			}
   299  		default:
   300  			fs := &fieldSpec{name: f.Name}
   301  			tag := f.Tag.Get("redis")
   302  			p := strings.Split(tag, ",")
   303  			if len(p) > 0 {
   304  				if p[0] == "-" {
   305  					continue
   306  				}
   307  				if len(p[0]) > 0 {
   308  					fs.name = p[0]
   309  				}
   310  				for _, s := range p[1:] {
   311  					switch s {
   312  					case "omitempty":
   313  						fs.omitEmpty = true
   314  					default:
   315  						panic(fmt.Errorf("redigo: unknown field tag %s for type %s", s, t.Name()))
   316  					}
   317  				}
   318  			}
   319  			d, found := depth[fs.name]
   320  			if !found {
   321  				d = 1 << 30
   322  			}
   323  			switch {
   324  			case len(index) == d:
   325  				// At same depth, remove from result.
   326  				delete(ss.m, fs.name)
   327  				j := 0
   328  				for i := 0; i < len(ss.l); i++ {
   329  					if fs.name != ss.l[i].name {
   330  						ss.l[j] = ss.l[i]
   331  						j += 1
   332  					}
   333  				}
   334  				ss.l = ss.l[:j]
   335  			case len(index) < d:
   336  				fs.index = make([]int, len(index)+1)
   337  				copy(fs.index, index)
   338  				fs.index[len(index)] = i
   339  				depth[fs.name] = len(index)
   340  				ss.m[fs.name] = fs
   341  				ss.l = append(ss.l, fs)
   342  			}
   343  		}
   344  	}
   345  }
   346  
   347  var (
   348  	structSpecMutex  sync.RWMutex
   349  	structSpecCache  = make(map[reflect.Type]*structSpec)
   350  	defaultFieldSpec = &fieldSpec{}
   351  )
   352  
   353  func structSpecForType(t reflect.Type) *structSpec {
   354  
   355  	structSpecMutex.RLock()
   356  	ss, found := structSpecCache[t]
   357  	structSpecMutex.RUnlock()
   358  	if found {
   359  		return ss
   360  	}
   361  
   362  	structSpecMutex.Lock()
   363  	defer structSpecMutex.Unlock()
   364  	ss, found = structSpecCache[t]
   365  	if found {
   366  		return ss
   367  	}
   368  
   369  	ss = &structSpec{m: make(map[string]*fieldSpec)}
   370  	compileStructSpec(t, make(map[string]int), nil, ss)
   371  	structSpecCache[t] = ss
   372  	return ss
   373  }
   374  
   375  var errScanStructValue = errors.New("redigo.ScanStruct: value must be non-nil pointer to a struct")
   376  
   377  // ScanStruct scans alternating names and values from src to a struct. The
   378  // HGETALL and CONFIG GET commands return replies in this format.
   379  //
   380  // ScanStruct uses exported field names to match values in the response. Use
   381  // 'redis' field tag to override the name:
   382  //
   383  //      Field int `redis:"myName"`
   384  //
   385  // Fields with the tag redis:"-" are ignored.
   386  //
   387  // Each field uses RedisScan if available otherwise:
   388  // Integer, float, boolean, string and []byte fields are supported. Scan uses the
   389  // standard strconv package to convert bulk string values to numeric and
   390  // boolean types.
   391  //
   392  // If a src element is nil, then the corresponding field is not modified.
   393  func ScanStruct(src []interface{}, dest interface{}) error {
   394  	d := reflect.ValueOf(dest)
   395  	if d.Kind() != reflect.Ptr || d.IsNil() {
   396  		return errScanStructValue
   397  	}
   398  	d = d.Elem()
   399  	if d.Kind() != reflect.Struct {
   400  		return errScanStructValue
   401  	}
   402  	ss := structSpecForType(d.Type())
   403  
   404  	if len(src)%2 != 0 {
   405  		return errors.New("redigo.ScanStruct: number of values not a multiple of 2")
   406  	}
   407  
   408  	for i := 0; i < len(src); i += 2 {
   409  		s := src[i+1]
   410  		if s == nil {
   411  			continue
   412  		}
   413  		name, ok := src[i].([]byte)
   414  		if !ok {
   415  			return fmt.Errorf("redigo.ScanStruct: key %d not a bulk string value", i)
   416  		}
   417  		fs := ss.fieldSpec(name)
   418  		if fs == nil {
   419  			continue
   420  		}
   421  		if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil {
   422  			return fmt.Errorf("redigo.ScanStruct: cannot assign field %s: %v", fs.name, err)
   423  		}
   424  	}
   425  	return nil
   426  }
   427  
   428  var (
   429  	errScanSliceValue = errors.New("redigo.ScanSlice: dest must be non-nil pointer to a struct")
   430  )
   431  
   432  // ScanSlice scans src to the slice pointed to by dest. The elements the dest
   433  // slice must be integer, float, boolean, string, struct or pointer to struct
   434  // values.
   435  //
   436  // Struct fields must be integer, float, boolean or string values. All struct
   437  // fields are used unless a subset is specified using fieldNames.
   438  func ScanSlice(src []interface{}, dest interface{}, fieldNames ...string) error {
   439  	d := reflect.ValueOf(dest)
   440  	if d.Kind() != reflect.Ptr || d.IsNil() {
   441  		return errScanSliceValue
   442  	}
   443  	d = d.Elem()
   444  	if d.Kind() != reflect.Slice {
   445  		return errScanSliceValue
   446  	}
   447  
   448  	isPtr := false
   449  	t := d.Type().Elem()
   450  	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
   451  		isPtr = true
   452  		t = t.Elem()
   453  	}
   454  
   455  	if t.Kind() != reflect.Struct {
   456  		ensureLen(d, len(src))
   457  		for i, s := range src {
   458  			if s == nil {
   459  				continue
   460  			}
   461  			if err := convertAssignValue(d.Index(i), s); err != nil {
   462  				return fmt.Errorf("redigo.ScanSlice: cannot assign element %d: %v", i, err)
   463  			}
   464  		}
   465  		return nil
   466  	}
   467  
   468  	ss := structSpecForType(t)
   469  	fss := ss.l
   470  	if len(fieldNames) > 0 {
   471  		fss = make([]*fieldSpec, len(fieldNames))
   472  		for i, name := range fieldNames {
   473  			fss[i] = ss.m[name]
   474  			if fss[i] == nil {
   475  				return fmt.Errorf("redigo.ScanSlice: ScanSlice bad field name %s", name)
   476  			}
   477  		}
   478  	}
   479  
   480  	if len(fss) == 0 {
   481  		return errors.New("redigo.ScanSlice: no struct fields")
   482  	}
   483  
   484  	n := len(src) / len(fss)
   485  	if n*len(fss) != len(src) {
   486  		return errors.New("redigo.ScanSlice: length not a multiple of struct field count")
   487  	}
   488  
   489  	ensureLen(d, n)
   490  	for i := 0; i < n; i++ {
   491  		d := d.Index(i)
   492  		if isPtr {
   493  			if d.IsNil() {
   494  				d.Set(reflect.New(t))
   495  			}
   496  			d = d.Elem()
   497  		}
   498  		for j, fs := range fss {
   499  			s := src[i*len(fss)+j]
   500  			if s == nil {
   501  				continue
   502  			}
   503  			if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil {
   504  				return fmt.Errorf("redigo.ScanSlice: cannot assign element %d to field %s: %v", i*len(fss)+j, fs.name, err)
   505  			}
   506  		}
   507  	}
   508  	return nil
   509  }
   510  
   511  // Args is a helper for constructing command arguments from structured values.
   512  type Args []interface{}
   513  
   514  // Add returns the result of appending value to args.
   515  func (args Args) Add(value ...interface{}) Args {
   516  	return append(args, value...)
   517  }
   518  
   519  // AddFlat returns the result of appending the flattened value of v to args.
   520  //
   521  // Maps are flattened by appending the alternating keys and map values to args.
   522  //
   523  // Slices are flattened by appending the slice elements to args.
   524  //
   525  // Structs are flattened by appending the alternating names and values of
   526  // exported fields to args. If v is a nil struct pointer, then nothing is
   527  // appended. The 'redis' field tag overrides struct field names. See ScanStruct
   528  // for more information on the use of the 'redis' field tag.
   529  //
   530  // Other types are appended to args as is.
   531  func (args Args) AddFlat(v interface{}) Args {
   532  	rv := reflect.ValueOf(v)
   533  	switch rv.Kind() {
   534  	case reflect.Struct:
   535  		args = flattenStruct(args, rv)
   536  	case reflect.Slice:
   537  		for i := 0; i < rv.Len(); i++ {
   538  			args = append(args, rv.Index(i).Interface())
   539  		}
   540  	case reflect.Map:
   541  		for _, k := range rv.MapKeys() {
   542  			args = append(args, k.Interface(), rv.MapIndex(k).Interface())
   543  		}
   544  	case reflect.Ptr:
   545  		if rv.Type().Elem().Kind() == reflect.Struct {
   546  			if !rv.IsNil() {
   547  				args = flattenStruct(args, rv.Elem())
   548  			}
   549  		} else {
   550  			args = append(args, v)
   551  		}
   552  	default:
   553  		args = append(args, v)
   554  	}
   555  	return args
   556  }
   557  
   558  func flattenStruct(args Args, v reflect.Value) Args {
   559  	ss := structSpecForType(v.Type())
   560  	for _, fs := range ss.l {
   561  		fv := v.FieldByIndex(fs.index)
   562  		if fs.omitEmpty {
   563  			var empty = false
   564  			switch fv.Kind() {
   565  			case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
   566  				empty = fv.Len() == 0
   567  			case reflect.Bool:
   568  				empty = !fv.Bool()
   569  			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   570  				empty = fv.Int() == 0
   571  			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   572  				empty = fv.Uint() == 0
   573  			case reflect.Float32, reflect.Float64:
   574  				empty = fv.Float() == 0
   575  			case reflect.Interface, reflect.Ptr:
   576  				empty = fv.IsNil()
   577  			}
   578  			if empty {
   579  				continue
   580  			}
   581  		}
   582  		args = append(args, fs.name, fv.Interface())
   583  	}
   584  	return args
   585  }
   586  

View as plain text