github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/datastore/load.go (about)

     1  // Copyright 2011 Google Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache 2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package datastore
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"time"
    11  
    12  	"google.golang.org/appengine"
    13  	pb "google.golang.org/appengine/internal/datastore"
    14  )
    15  
    16  var (
    17  	typeOfBlobKey    = reflect.TypeOf(appengine.BlobKey(""))
    18  	typeOfByteSlice  = reflect.TypeOf([]byte(nil))
    19  	typeOfByteString = reflect.TypeOf(ByteString(nil))
    20  	typeOfGeoPoint   = reflect.TypeOf(appengine.GeoPoint{})
    21  	typeOfTime       = reflect.TypeOf(time.Time{})
    22  )
    23  
    24  // typeMismatchReason returns a string explaining why the property p could not
    25  // be stored in an entity field of type v.Type().
    26  func typeMismatchReason(p Property, v reflect.Value) string {
    27  	entityType := "empty"
    28  	switch p.Value.(type) {
    29  	case int64:
    30  		entityType = "int"
    31  	case bool:
    32  		entityType = "bool"
    33  	case string:
    34  		entityType = "string"
    35  	case float64:
    36  		entityType = "float"
    37  	case *Key:
    38  		entityType = "*datastore.Key"
    39  	case time.Time:
    40  		entityType = "time.Time"
    41  	case appengine.BlobKey:
    42  		entityType = "appengine.BlobKey"
    43  	case appengine.GeoPoint:
    44  		entityType = "appengine.GeoPoint"
    45  	case ByteString:
    46  		entityType = "datastore.ByteString"
    47  	case []byte:
    48  		entityType = "[]byte"
    49  	}
    50  	return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type())
    51  }
    52  
    53  type propertyLoader struct {
    54  	// m holds the number of times a substruct field like "Foo.Bar.Baz" has
    55  	// been seen so far. The map is constructed lazily.
    56  	m map[string]int
    57  }
    58  
    59  func (l *propertyLoader) load(codec *structCodec, structValue reflect.Value, p Property, requireSlice bool) string {
    60  	var v reflect.Value
    61  	// Traverse a struct's struct-typed fields.
    62  	for name := p.Name; ; {
    63  		decoder, ok := codec.byName[name]
    64  		if !ok {
    65  			return "no such struct field"
    66  		}
    67  		v = structValue.Field(decoder.index)
    68  		if !v.IsValid() {
    69  			return "no such struct field"
    70  		}
    71  		if !v.CanSet() {
    72  			return "cannot set struct field"
    73  		}
    74  
    75  		if decoder.substructCodec == nil {
    76  			break
    77  		}
    78  
    79  		if v.Kind() == reflect.Slice {
    80  			if l.m == nil {
    81  				l.m = make(map[string]int)
    82  			}
    83  			index := l.m[p.Name]
    84  			l.m[p.Name] = index + 1
    85  			for v.Len() <= index {
    86  				v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem()))
    87  			}
    88  			structValue = v.Index(index)
    89  			requireSlice = false
    90  		} else {
    91  			structValue = v
    92  		}
    93  		// Strip the "I." from "I.X".
    94  		name = name[len(codec.byIndex[decoder.index].name):]
    95  		codec = decoder.substructCodec
    96  	}
    97  
    98  	var slice reflect.Value
    99  	if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
   100  		slice = v
   101  		v = reflect.New(v.Type().Elem()).Elem()
   102  	} else if requireSlice {
   103  		return "multiple-valued property requires a slice field type"
   104  	}
   105  
   106  	// Convert indexValues to a Go value with a meaning derived from the
   107  	// destination type.
   108  	pValue := p.Value
   109  	if iv, ok := pValue.(indexValue); ok {
   110  		meaning := pb.Property_NO_MEANING
   111  		switch v.Type() {
   112  		case typeOfBlobKey:
   113  			meaning = pb.Property_BLOBKEY
   114  		case typeOfByteSlice:
   115  			meaning = pb.Property_BLOB
   116  		case typeOfByteString:
   117  			meaning = pb.Property_BYTESTRING
   118  		case typeOfGeoPoint:
   119  			meaning = pb.Property_GEORSS_POINT
   120  		case typeOfTime:
   121  			meaning = pb.Property_GD_WHEN
   122  		}
   123  		var err error
   124  		pValue, err = propValue(iv.value, meaning)
   125  		if err != nil {
   126  			return err.Error()
   127  		}
   128  	}
   129  
   130  	switch v.Kind() {
   131  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   132  		x, ok := pValue.(int64)
   133  		if !ok && pValue != nil {
   134  			return typeMismatchReason(p, v)
   135  		}
   136  		if v.OverflowInt(x) {
   137  			return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type())
   138  		}
   139  		v.SetInt(x)
   140  	case reflect.Bool:
   141  		x, ok := pValue.(bool)
   142  		if !ok && pValue != nil {
   143  			return typeMismatchReason(p, v)
   144  		}
   145  		v.SetBool(x)
   146  	case reflect.String:
   147  		switch x := pValue.(type) {
   148  		case appengine.BlobKey:
   149  			v.SetString(string(x))
   150  		case ByteString:
   151  			v.SetString(string(x))
   152  		case string:
   153  			v.SetString(x)
   154  		default:
   155  			if pValue != nil {
   156  				return typeMismatchReason(p, v)
   157  			}
   158  		}
   159  	case reflect.Float32, reflect.Float64:
   160  		x, ok := pValue.(float64)
   161  		if !ok && pValue != nil {
   162  			return typeMismatchReason(p, v)
   163  		}
   164  		if v.OverflowFloat(x) {
   165  			return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type())
   166  		}
   167  		v.SetFloat(x)
   168  	case reflect.Ptr:
   169  		x, ok := pValue.(*Key)
   170  		if !ok && pValue != nil {
   171  			return typeMismatchReason(p, v)
   172  		}
   173  		if _, ok := v.Interface().(*Key); !ok {
   174  			return typeMismatchReason(p, v)
   175  		}
   176  		v.Set(reflect.ValueOf(x))
   177  	case reflect.Struct:
   178  		switch v.Type() {
   179  		case typeOfTime:
   180  			x, ok := pValue.(time.Time)
   181  			if !ok && pValue != nil {
   182  				return typeMismatchReason(p, v)
   183  			}
   184  			v.Set(reflect.ValueOf(x))
   185  		case typeOfGeoPoint:
   186  			x, ok := pValue.(appengine.GeoPoint)
   187  			if !ok && pValue != nil {
   188  				return typeMismatchReason(p, v)
   189  			}
   190  			v.Set(reflect.ValueOf(x))
   191  		default:
   192  			return typeMismatchReason(p, v)
   193  		}
   194  	case reflect.Slice:
   195  		x, ok := pValue.([]byte)
   196  		if !ok {
   197  			if y, yok := pValue.(ByteString); yok {
   198  				x, ok = []byte(y), true
   199  			}
   200  		}
   201  		if !ok && pValue != nil {
   202  			return typeMismatchReason(p, v)
   203  		}
   204  		if v.Type().Elem().Kind() != reflect.Uint8 {
   205  			return typeMismatchReason(p, v)
   206  		}
   207  		v.SetBytes(x)
   208  	default:
   209  		return typeMismatchReason(p, v)
   210  	}
   211  	if slice.IsValid() {
   212  		slice.Set(reflect.Append(slice, v))
   213  	}
   214  	return ""
   215  }
   216  
   217  // loadEntity loads an EntityProto into PropertyLoadSaver or struct pointer.
   218  func loadEntity(dst interface{}, src *pb.EntityProto) (err error) {
   219  	props, err := protoToProperties(src)
   220  	if err != nil {
   221  		return err
   222  	}
   223  	if e, ok := dst.(PropertyLoadSaver); ok {
   224  		return e.Load(props)
   225  	}
   226  	return LoadStruct(dst, props)
   227  }
   228  
   229  func (s structPLS) Load(props []Property) error {
   230  	var fieldName, reason string
   231  	var l propertyLoader
   232  	for _, p := range props {
   233  		if errStr := l.load(s.codec, s.v, p, p.Multiple); errStr != "" {
   234  			// We don't return early, as we try to load as many properties as possible.
   235  			// It is valid to load an entity into a struct that cannot fully represent it.
   236  			// That case returns an error, but the caller is free to ignore it.
   237  			fieldName, reason = p.Name, errStr
   238  		}
   239  	}
   240  	if reason != "" {
   241  		return &ErrFieldMismatch{
   242  			StructType: s.v.Type(),
   243  			FieldName:  fieldName,
   244  			Reason:     reason,
   245  		}
   246  	}
   247  	return nil
   248  }
   249  
   250  func protoToProperties(src *pb.EntityProto) ([]Property, error) {
   251  	props, rawProps := src.Property, src.RawProperty
   252  	out := make([]Property, 0, len(props)+len(rawProps))
   253  	for {
   254  		var (
   255  			x       *pb.Property
   256  			noIndex bool
   257  		)
   258  		if len(props) > 0 {
   259  			x, props = props[0], props[1:]
   260  		} else if len(rawProps) > 0 {
   261  			x, rawProps = rawProps[0], rawProps[1:]
   262  			noIndex = true
   263  		} else {
   264  			break
   265  		}
   266  
   267  		var value interface{}
   268  		if x.Meaning != nil && *x.Meaning == pb.Property_INDEX_VALUE {
   269  			value = indexValue{x.Value}
   270  		} else {
   271  			var err error
   272  			value, err = propValue(x.Value, x.GetMeaning())
   273  			if err != nil {
   274  				return nil, err
   275  			}
   276  		}
   277  		out = append(out, Property{
   278  			Name:     x.GetName(),
   279  			Value:    value,
   280  			NoIndex:  noIndex,
   281  			Multiple: x.GetMultiple(),
   282  		})
   283  	}
   284  	return out, nil
   285  }
   286  
   287  // propValue returns a Go value that combines the raw PropertyValue with a
   288  // meaning. For example, an Int64Value with GD_WHEN becomes a time.Time.
   289  func propValue(v *pb.PropertyValue, m pb.Property_Meaning) (interface{}, error) {
   290  	switch {
   291  	case v.Int64Value != nil:
   292  		if m == pb.Property_GD_WHEN {
   293  			return fromUnixMicro(*v.Int64Value), nil
   294  		} else {
   295  			return *v.Int64Value, nil
   296  		}
   297  	case v.BooleanValue != nil:
   298  		return *v.BooleanValue, nil
   299  	case v.StringValue != nil:
   300  		if m == pb.Property_BLOB {
   301  			return []byte(*v.StringValue), nil
   302  		} else if m == pb.Property_BLOBKEY {
   303  			return appengine.BlobKey(*v.StringValue), nil
   304  		} else if m == pb.Property_BYTESTRING {
   305  			return ByteString(*v.StringValue), nil
   306  		} else {
   307  			return *v.StringValue, nil
   308  		}
   309  	case v.DoubleValue != nil:
   310  		return *v.DoubleValue, nil
   311  	case v.Referencevalue != nil:
   312  		key, err := referenceValueToKey(v.Referencevalue)
   313  		if err != nil {
   314  			return nil, err
   315  		}
   316  		return key, nil
   317  	case v.Pointvalue != nil:
   318  		// NOTE: Strangely, latitude maps to X, longitude to Y.
   319  		return appengine.GeoPoint{Lat: v.Pointvalue.GetX(), Lng: v.Pointvalue.GetY()}, nil
   320  	}
   321  	return nil, nil
   322  }
   323  
   324  // indexValue is a Property value that is created when entities are loaded from
   325  // an index, such as from a projection query.
   326  //
   327  // Such Property values do not contain all of the metadata required to be
   328  // faithfully represented as a Go value, and are instead represented as an
   329  // opaque indexValue. Load the properties into a concrete struct type (e.g. by
   330  // passing a struct pointer to Iterator.Next) to reconstruct actual Go values
   331  // of type int, string, time.Time, etc.
   332  type indexValue struct {
   333  	value *pb.PropertyValue
   334  }