Home | History | Annotate | Download | only in datastore
      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 	"strings"
     11 	"sync"
     12 	"unicode"
     13 )
     14 
     15 // Entities with more than this many indexed properties will not be saved.
     16 const maxIndexedProperties = 20000
     17 
     18 // []byte fields more than 1 megabyte long will not be loaded or saved.
     19 const maxBlobLen = 1 << 20
     20 
     21 // Property is a name/value pair plus some metadata. A datastore entity's
     22 // contents are loaded and saved as a sequence of Properties. An entity can
     23 // have multiple Properties with the same name, provided that p.Multiple is
     24 // true on all of that entity's Properties with that name.
     25 type Property struct {
     26 	// Name is the property name.
     27 	Name string
     28 	// Value is the property value. The valid types are:
     29 	//	- int64
     30 	//	- bool
     31 	//	- string
     32 	//	- float64
     33 	//	- ByteString
     34 	//	- *Key
     35 	//	- time.Time
     36 	//	- appengine.BlobKey
     37 	//	- appengine.GeoPoint
     38 	//	- []byte (up to 1 megabyte in length)
     39 	//	- *Entity (representing a nested struct)
     40 	// This set is smaller than the set of valid struct field types that the
     41 	// datastore can load and save. A Property Value cannot be a slice (apart
     42 	// from []byte); use multiple Properties instead. Also, a Value's type
     43 	// must be explicitly on the list above; it is not sufficient for the
     44 	// underlying type to be on that list. For example, a Value of "type
     45 	// myInt64 int64" is invalid. Smaller-width integers and floats are also
     46 	// invalid. Again, this is more restrictive than the set of valid struct
     47 	// field types.
     48 	//
     49 	// A Value will have an opaque type when loading entities from an index,
     50 	// such as via a projection query. Load entities into a struct instead
     51 	// of a PropertyLoadSaver when using a projection query.
     52 	//
     53 	// A Value may also be the nil interface value; this is equivalent to
     54 	// Python's None but not directly representable by a Go struct. Loading
     55 	// a nil-valued property into a struct will set that field to the zero
     56 	// value.
     57 	Value interface{}
     58 	// NoIndex is whether the datastore cannot index this property.
     59 	NoIndex bool
     60 	// Multiple is whether the entity can have multiple properties with
     61 	// the same name. Even if a particular instance only has one property with
     62 	// a certain name, Multiple should be true if a struct would best represent
     63 	// it as a field of type []T instead of type T.
     64 	Multiple bool
     65 }
     66 
     67 // An Entity is the value type for a nested struct.
     68 // This type is only used for a Property's Value.
     69 type Entity struct {
     70 	Key        *Key
     71 	Properties []Property
     72 }
     73 
     74 // ByteString is a short byte slice (up to 1500 bytes) that can be indexed.
     75 type ByteString []byte
     76 
     77 // PropertyLoadSaver can be converted from and to a slice of Properties.
     78 type PropertyLoadSaver interface {
     79 	Load([]Property) error
     80 	Save() ([]Property, error)
     81 }
     82 
     83 // PropertyList converts a []Property to implement PropertyLoadSaver.
     84 type PropertyList []Property
     85 
     86 var (
     87 	typeOfPropertyLoadSaver = reflect.TypeOf((*PropertyLoadSaver)(nil)).Elem()
     88 	typeOfPropertyList      = reflect.TypeOf(PropertyList(nil))
     89 )
     90 
     91 // Load loads all of the provided properties into l.
     92 // It does not first reset *l to an empty slice.
     93 func (l *PropertyList) Load(p []Property) error {
     94 	*l = append(*l, p...)
     95 	return nil
     96 }
     97 
     98 // Save saves all of l's properties as a slice or Properties.
     99 func (l *PropertyList) Save() ([]Property, error) {
    100 	return *l, nil
    101 }
    102 
    103 // validPropertyName returns whether name consists of one or more valid Go
    104 // identifiers joined by ".".
    105 func validPropertyName(name string) bool {
    106 	if name == "" {
    107 		return false
    108 	}
    109 	for _, s := range strings.Split(name, ".") {
    110 		if s == "" {
    111 			return false
    112 		}
    113 		first := true
    114 		for _, c := range s {
    115 			if first {
    116 				first = false
    117 				if c != '_' && !unicode.IsLetter(c) {
    118 					return false
    119 				}
    120 			} else {
    121 				if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
    122 					return false
    123 				}
    124 			}
    125 		}
    126 	}
    127 	return true
    128 }
    129 
    130 // structCodec describes how to convert a struct to and from a sequence of
    131 // properties.
    132 type structCodec struct {
    133 	// fields gives the field codec for the structTag with the given name.
    134 	fields map[string]fieldCodec
    135 	// hasSlice is whether a struct or any of its nested or embedded structs
    136 	// has a slice-typed field (other than []byte).
    137 	hasSlice bool
    138 	// keyField is the index of a *Key field with structTag __key__.
    139 	// This field is not relevant for the top level struct, only for
    140 	// nested structs.
    141 	keyField int
    142 	// complete is whether the structCodec is complete. An incomplete
    143 	// structCodec may be encountered when walking a recursive struct.
    144 	complete bool
    145 }
    146 
    147 // fieldCodec is a struct field's index and, if that struct field's type is
    148 // itself a struct, that substruct's structCodec.
    149 type fieldCodec struct {
    150 	// path is the index path to the field
    151 	path    []int
    152 	noIndex bool
    153 	// omitEmpty indicates that the field should be omitted on save
    154 	// if empty.
    155 	omitEmpty bool
    156 	// structCodec is the codec fot the struct field at index 'path',
    157 	// or nil if the field is not a struct.
    158 	structCodec *structCodec
    159 }
    160 
    161 // structCodecs collects the structCodecs that have already been calculated.
    162 var (
    163 	structCodecsMutex sync.Mutex
    164 	structCodecs      = make(map[reflect.Type]*structCodec)
    165 )
    166 
    167 // getStructCodec returns the structCodec for the given struct type.
    168 func getStructCodec(t reflect.Type) (*structCodec, error) {
    169 	structCodecsMutex.Lock()
    170 	defer structCodecsMutex.Unlock()
    171 	return getStructCodecLocked(t)
    172 }
    173 
    174 // getStructCodecLocked implements getStructCodec. The structCodecsMutex must
    175 // be held when calling this function.
    176 func getStructCodecLocked(t reflect.Type) (ret *structCodec, retErr error) {
    177 	c, ok := structCodecs[t]
    178 	if ok {
    179 		return c, nil
    180 	}
    181 	c = &structCodec{
    182 		fields: make(map[string]fieldCodec),
    183 		// We initialize keyField to -1 so that the zero-value is not
    184 		// misinterpreted as index 0.
    185 		keyField: -1,
    186 	}
    187 
    188 	// Add c to the structCodecs map before we are sure it is good. If t is
    189 	// a recursive type, it needs to find the incomplete entry for itself in
    190 	// the map.
    191 	structCodecs[t] = c
    192 	defer func() {
    193 		if retErr != nil {
    194 			delete(structCodecs, t)
    195 		}
    196 	}()
    197 
    198 	for i := 0; i < t.NumField(); i++ {
    199 		f := t.Field(i)
    200 		// Skip unexported fields.
    201 		// Note that if f is an anonymous, unexported struct field,
    202 		// we will promote its fields.
    203 		if f.PkgPath != "" && !f.Anonymous {
    204 			continue
    205 		}
    206 
    207 		tags := strings.Split(f.Tag.Get("datastore"), ",")
    208 		name := tags[0]
    209 		opts := make(map[string]bool)
    210 		for _, t := range tags[1:] {
    211 			opts[t] = true
    212 		}
    213 		switch {
    214 		case name == "":
    215 			if !f.Anonymous {
    216 				name = f.Name
    217 			}
    218 		case name == "-":
    219 			continue
    220 		case name == "__key__":
    221 			if f.Type != typeOfKeyPtr {
    222 				return nil, fmt.Errorf("datastore: __key__ field on struct %v is not a *datastore.Key", t)
    223 			}
    224 			c.keyField = i
    225 		case !validPropertyName(name):
    226 			return nil, fmt.Errorf("datastore: struct tag has invalid property name: %q", name)
    227 		}
    228 
    229 		substructType, fIsSlice := reflect.Type(nil), false
    230 		switch f.Type.Kind() {
    231 		case reflect.Struct:
    232 			substructType = f.Type
    233 		case reflect.Slice:
    234 			if f.Type.Elem().Kind() == reflect.Struct {
    235 				substructType = f.Type.Elem()
    236 			}
    237 			fIsSlice = f.Type != typeOfByteSlice
    238 			c.hasSlice = c.hasSlice || fIsSlice
    239 		}
    240 
    241 		var sub *structCodec
    242 		if substructType != nil && substructType != typeOfTime && substructType != typeOfGeoPoint {
    243 			var err error
    244 			sub, err = getStructCodecLocked(substructType)
    245 			if err != nil {
    246 				return nil, err
    247 			}
    248 			if !sub.complete {
    249 				return nil, fmt.Errorf("datastore: recursive struct: field %q", f.Name)
    250 			}
    251 			if fIsSlice && sub.hasSlice {
    252 				return nil, fmt.Errorf(
    253 					"datastore: flattening nested structs leads to a slice of slices: field %q", f.Name)
    254 			}
    255 			c.hasSlice = c.hasSlice || sub.hasSlice
    256 			// If f is an anonymous struct field, we promote the substruct's fields up to this level
    257 			// in the linked list of struct codecs.
    258 			if f.Anonymous {
    259 				for subname, subfield := range sub.fields {
    260 					if name != "" {
    261 						subname = name + "." + subname
    262 					}
    263 					if _, ok := c.fields[subname]; ok {
    264 						return nil, fmt.Errorf("datastore: struct tag has repeated property name: %q", subname)
    265 					}
    266 					c.fields[subname] = fieldCodec{
    267 						path:        append([]int{i}, subfield.path...),
    268 						noIndex:     subfield.noIndex || opts["noindex"],
    269 						omitEmpty:   subfield.omitEmpty,
    270 						structCodec: subfield.structCodec,
    271 					}
    272 				}
    273 				continue
    274 			}
    275 		}
    276 
    277 		if _, ok := c.fields[name]; ok {
    278 			return nil, fmt.Errorf("datastore: struct tag has repeated property name: %q", name)
    279 		}
    280 		c.fields[name] = fieldCodec{
    281 			path:        []int{i},
    282 			noIndex:     opts["noindex"],
    283 			omitEmpty:   opts["omitempty"],
    284 			structCodec: sub,
    285 		}
    286 	}
    287 	c.complete = true
    288 	return c, nil
    289 }
    290 
    291 // structPLS adapts a struct to be a PropertyLoadSaver.
    292 type structPLS struct {
    293 	v     reflect.Value
    294 	codec *structCodec
    295 }
    296 
    297 // newStructPLS returns a structPLS, which implements the
    298 // PropertyLoadSaver interface, for the struct pointer p.
    299 func newStructPLS(p interface{}) (*structPLS, error) {
    300 	v := reflect.ValueOf(p)
    301 	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
    302 		return nil, ErrInvalidEntityType
    303 	}
    304 	v = v.Elem()
    305 	codec, err := getStructCodec(v.Type())
    306 	if err != nil {
    307 		return nil, err
    308 	}
    309 	return &structPLS{v, codec}, nil
    310 }
    311 
    312 // LoadStruct loads the properties from p to dst.
    313 // dst must be a struct pointer.
    314 func LoadStruct(dst interface{}, p []Property) error {
    315 	x, err := newStructPLS(dst)
    316 	if err != nil {
    317 		return err
    318 	}
    319 	return x.Load(p)
    320 }
    321 
    322 // SaveStruct returns the properties from src as a slice of Properties.
    323 // src must be a struct pointer.
    324 func SaveStruct(src interface{}) ([]Property, error) {
    325 	x, err := newStructPLS(src)
    326 	if err != nil {
    327 		return nil, err
    328 	}
    329 	return x.Save()
    330 }
    331