github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/datastore/datastore.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 "errors" 9 "fmt" 10 "reflect" 11 12 "github.com/golang/protobuf/proto" 13 "golang.org/x/net/context" 14 15 "google.golang.org/appengine" 16 "google.golang.org/appengine/internal" 17 pb "google.golang.org/appengine/internal/datastore" 18 ) 19 20 var ( 21 // ErrInvalidEntityType is returned when functions like Get or Next are 22 // passed a dst or src argument of invalid type. 23 ErrInvalidEntityType = errors.New("datastore: invalid entity type") 24 // ErrInvalidKey is returned when an invalid key is presented. 25 ErrInvalidKey = errors.New("datastore: invalid key") 26 // ErrNoSuchEntity is returned when no entity was found for a given key. 27 ErrNoSuchEntity = errors.New("datastore: no such entity") 28 ) 29 30 // ErrFieldMismatch is returned when a field is to be loaded into a different 31 // type than the one it was stored from, or when a field is missing or 32 // unexported in the destination struct. 33 // StructType is the type of the struct pointed to by the destination argument 34 // passed to Get or to Iterator.Next. 35 type ErrFieldMismatch struct { 36 StructType reflect.Type 37 FieldName string 38 Reason string 39 } 40 41 func (e *ErrFieldMismatch) Error() string { 42 return fmt.Sprintf("datastore: cannot load field %q into a %q: %s", 43 e.FieldName, e.StructType, e.Reason) 44 } 45 46 // protoToKey converts a Reference proto to a *Key. 47 func protoToKey(r *pb.Reference) (k *Key, err error) { 48 appID := r.GetApp() 49 namespace := r.GetNameSpace() 50 for _, e := range r.Path.Element { 51 k = &Key{ 52 kind: e.GetType(), 53 stringID: e.GetName(), 54 intID: e.GetId(), 55 parent: k, 56 appID: appID, 57 namespace: namespace, 58 } 59 if !k.valid() { 60 return nil, ErrInvalidKey 61 } 62 } 63 return 64 } 65 66 // keyToProto converts a *Key to a Reference proto. 67 func keyToProto(defaultAppID string, k *Key) *pb.Reference { 68 appID := k.appID 69 if appID == "" { 70 appID = defaultAppID 71 } 72 n := 0 73 for i := k; i != nil; i = i.parent { 74 n++ 75 } 76 e := make([]*pb.Path_Element, n) 77 for i := k; i != nil; i = i.parent { 78 n-- 79 e[n] = &pb.Path_Element{ 80 Type: &i.kind, 81 } 82 // At most one of {Name,Id} should be set. 83 // Neither will be set for incomplete keys. 84 if i.stringID != "" { 85 e[n].Name = &i.stringID 86 } else if i.intID != 0 { 87 e[n].Id = &i.intID 88 } 89 } 90 var namespace *string 91 if k.namespace != "" { 92 namespace = proto.String(k.namespace) 93 } 94 return &pb.Reference{ 95 App: proto.String(appID), 96 NameSpace: namespace, 97 Path: &pb.Path{ 98 Element: e, 99 }, 100 } 101 } 102 103 // multiKeyToProto is a batch version of keyToProto. 104 func multiKeyToProto(appID string, key []*Key) []*pb.Reference { 105 ret := make([]*pb.Reference, len(key)) 106 for i, k := range key { 107 ret[i] = keyToProto(appID, k) 108 } 109 return ret 110 } 111 112 // multiValid is a batch version of Key.valid. It returns an error, not a 113 // []bool. 114 func multiValid(key []*Key) error { 115 invalid := false 116 for _, k := range key { 117 if !k.valid() { 118 invalid = true 119 break 120 } 121 } 122 if !invalid { 123 return nil 124 } 125 err := make(appengine.MultiError, len(key)) 126 for i, k := range key { 127 if !k.valid() { 128 err[i] = ErrInvalidKey 129 } 130 } 131 return err 132 } 133 134 // It's unfortunate that the two semantically equivalent concepts pb.Reference 135 // and pb.PropertyValue_ReferenceValue aren't the same type. For example, the 136 // two have different protobuf field numbers. 137 138 // referenceValueToKey is the same as protoToKey except the input is a 139 // PropertyValue_ReferenceValue instead of a Reference. 140 func referenceValueToKey(r *pb.PropertyValue_ReferenceValue) (k *Key, err error) { 141 appID := r.GetApp() 142 namespace := r.GetNameSpace() 143 for _, e := range r.Pathelement { 144 k = &Key{ 145 kind: e.GetType(), 146 stringID: e.GetName(), 147 intID: e.GetId(), 148 parent: k, 149 appID: appID, 150 namespace: namespace, 151 } 152 if !k.valid() { 153 return nil, ErrInvalidKey 154 } 155 } 156 return 157 } 158 159 // keyToReferenceValue is the same as keyToProto except the output is a 160 // PropertyValue_ReferenceValue instead of a Reference. 161 func keyToReferenceValue(defaultAppID string, k *Key) *pb.PropertyValue_ReferenceValue { 162 ref := keyToProto(defaultAppID, k) 163 pe := make([]*pb.PropertyValue_ReferenceValue_PathElement, len(ref.Path.Element)) 164 for i, e := range ref.Path.Element { 165 pe[i] = &pb.PropertyValue_ReferenceValue_PathElement{ 166 Type: e.Type, 167 Id: e.Id, 168 Name: e.Name, 169 } 170 } 171 return &pb.PropertyValue_ReferenceValue{ 172 App: ref.App, 173 NameSpace: ref.NameSpace, 174 Pathelement: pe, 175 } 176 } 177 178 type multiArgType int 179 180 const ( 181 multiArgTypeInvalid multiArgType = iota 182 multiArgTypePropertyLoadSaver 183 multiArgTypeStruct 184 multiArgTypeStructPtr 185 multiArgTypeInterface 186 ) 187 188 // checkMultiArg checks that v has type []S, []*S, []I, or []P, for some struct 189 // type S, for some interface type I, or some non-interface non-pointer type P 190 // such that P or *P implements PropertyLoadSaver. 191 // 192 // It returns what category the slice's elements are, and the reflect.Type 193 // that represents S, I or P. 194 // 195 // As a special case, PropertyList is an invalid type for v. 196 func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) { 197 if v.Kind() != reflect.Slice { 198 return multiArgTypeInvalid, nil 199 } 200 if v.Type() == typeOfPropertyList { 201 return multiArgTypeInvalid, nil 202 } 203 elemType = v.Type().Elem() 204 if reflect.PtrTo(elemType).Implements(typeOfPropertyLoadSaver) { 205 return multiArgTypePropertyLoadSaver, elemType 206 } 207 switch elemType.Kind() { 208 case reflect.Struct: 209 return multiArgTypeStruct, elemType 210 case reflect.Interface: 211 return multiArgTypeInterface, elemType 212 case reflect.Ptr: 213 elemType = elemType.Elem() 214 if elemType.Kind() == reflect.Struct { 215 return multiArgTypeStructPtr, elemType 216 } 217 } 218 return multiArgTypeInvalid, nil 219 } 220 221 // Get loads the entity stored for k into dst, which must be a struct pointer 222 // or implement PropertyLoadSaver. If there is no such entity for the key, Get 223 // returns ErrNoSuchEntity. 224 // 225 // The values of dst's unmatched struct fields are not modified, and matching 226 // slice-typed fields are not reset before appending to them. In particular, it 227 // is recommended to pass a pointer to a zero valued struct on each Get call. 228 // 229 // ErrFieldMismatch is returned when a field is to be loaded into a different 230 // type than the one it was stored from, or when a field is missing or 231 // unexported in the destination struct. ErrFieldMismatch is only returned if 232 // dst is a struct pointer. 233 func Get(c context.Context, key *Key, dst interface{}) error { 234 if dst == nil { // GetMulti catches nil interface; we need to catch nil ptr here 235 return ErrInvalidEntityType 236 } 237 err := GetMulti(c, []*Key{key}, []interface{}{dst}) 238 if me, ok := err.(appengine.MultiError); ok { 239 return me[0] 240 } 241 return err 242 } 243 244 // GetMulti is a batch version of Get. 245 // 246 // dst must be a []S, []*S, []I or []P, for some struct type S, some interface 247 // type I, or some non-interface non-pointer type P such that P or *P 248 // implements PropertyLoadSaver. If an []I, each element must be a valid dst 249 // for Get: it must be a struct pointer or implement PropertyLoadSaver. 250 // 251 // As a special case, PropertyList is an invalid type for dst, even though a 252 // PropertyList is a slice of structs. It is treated as invalid to avoid being 253 // mistakenly passed when []PropertyList was intended. 254 func GetMulti(c context.Context, key []*Key, dst interface{}) error { 255 v := reflect.ValueOf(dst) 256 multiArgType, _ := checkMultiArg(v) 257 if multiArgType == multiArgTypeInvalid { 258 return errors.New("datastore: dst has invalid type") 259 } 260 if len(key) != v.Len() { 261 return errors.New("datastore: key and dst slices have different length") 262 } 263 if len(key) == 0 { 264 return nil 265 } 266 if err := multiValid(key); err != nil { 267 return err 268 } 269 req := &pb.GetRequest{ 270 Key: multiKeyToProto(internal.FullyQualifiedAppID(c), key), 271 } 272 res := &pb.GetResponse{} 273 if err := internal.Call(c, "datastore_v3", "Get", req, res); err != nil { 274 return err 275 } 276 if len(key) != len(res.Entity) { 277 return errors.New("datastore: internal error: server returned the wrong number of entities") 278 } 279 multiErr, any := make(appengine.MultiError, len(key)), false 280 for i, e := range res.Entity { 281 if e.Entity == nil { 282 multiErr[i] = ErrNoSuchEntity 283 } else { 284 elem := v.Index(i) 285 if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct { 286 elem = elem.Addr() 287 } 288 if multiArgType == multiArgTypeStructPtr && elem.IsNil() { 289 elem.Set(reflect.New(elem.Type().Elem())) 290 } 291 multiErr[i] = loadEntity(elem.Interface(), e.Entity) 292 } 293 if multiErr[i] != nil { 294 any = true 295 } 296 } 297 if any { 298 return multiErr 299 } 300 return nil 301 } 302 303 // Put saves the entity src into the datastore with key k. src must be a struct 304 // pointer or implement PropertyLoadSaver; if a struct pointer then any 305 // unexported fields of that struct will be skipped. If k is an incomplete key, 306 // the returned key will be a unique key generated by the datastore. 307 func Put(c context.Context, key *Key, src interface{}) (*Key, error) { 308 k, err := PutMulti(c, []*Key{key}, []interface{}{src}) 309 if err != nil { 310 if me, ok := err.(appengine.MultiError); ok { 311 return nil, me[0] 312 } 313 return nil, err 314 } 315 return k[0], nil 316 } 317 318 // PutMulti is a batch version of Put. 319 // 320 // src must satisfy the same conditions as the dst argument to GetMulti. 321 func PutMulti(c context.Context, key []*Key, src interface{}) ([]*Key, error) { 322 v := reflect.ValueOf(src) 323 multiArgType, _ := checkMultiArg(v) 324 if multiArgType == multiArgTypeInvalid { 325 return nil, errors.New("datastore: src has invalid type") 326 } 327 if len(key) != v.Len() { 328 return nil, errors.New("datastore: key and src slices have different length") 329 } 330 if len(key) == 0 { 331 return nil, nil 332 } 333 appID := internal.FullyQualifiedAppID(c) 334 if err := multiValid(key); err != nil { 335 return nil, err 336 } 337 req := &pb.PutRequest{} 338 for i := range key { 339 elem := v.Index(i) 340 if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct { 341 elem = elem.Addr() 342 } 343 sProto, err := saveEntity(appID, key[i], elem.Interface()) 344 if err != nil { 345 return nil, err 346 } 347 req.Entity = append(req.Entity, sProto) 348 } 349 res := &pb.PutResponse{} 350 if err := internal.Call(c, "datastore_v3", "Put", req, res); err != nil { 351 return nil, err 352 } 353 if len(key) != len(res.Key) { 354 return nil, errors.New("datastore: internal error: server returned the wrong number of keys") 355 } 356 ret := make([]*Key, len(key)) 357 for i := range ret { 358 var err error 359 ret[i], err = protoToKey(res.Key[i]) 360 if err != nil || ret[i].Incomplete() { 361 return nil, errors.New("datastore: internal error: server returned an invalid key") 362 } 363 } 364 return ret, nil 365 } 366 367 // Delete deletes the entity for the given key. 368 func Delete(c context.Context, key *Key) error { 369 err := DeleteMulti(c, []*Key{key}) 370 if me, ok := err.(appengine.MultiError); ok { 371 return me[0] 372 } 373 return err 374 } 375 376 // DeleteMulti is a batch version of Delete. 377 func DeleteMulti(c context.Context, key []*Key) error { 378 if len(key) == 0 { 379 return nil 380 } 381 if err := multiValid(key); err != nil { 382 return err 383 } 384 req := &pb.DeleteRequest{ 385 Key: multiKeyToProto(internal.FullyQualifiedAppID(c), key), 386 } 387 res := &pb.DeleteResponse{} 388 return internal.Call(c, "datastore_v3", "Delete", req, res) 389 } 390 391 func namespaceMod(m proto.Message, namespace string) { 392 // pb.Query is the only type that has a name_space field. 393 // All other namespace support in datastore is in the keys. 394 switch m := m.(type) { 395 case *pb.Query: 396 if m.NameSpace == nil { 397 m.NameSpace = &namespace 398 } 399 } 400 } 401 402 func init() { 403 internal.NamespaceMods["datastore_v3"] = namespaceMod 404 internal.RegisterErrorCodeMap("datastore_v3", pb.Error_ErrorCode_name) 405 internal.RegisterTimeoutErrorCode("datastore_v3", int32(pb.Error_TIMEOUT)) 406 }