// DelQuery will delete (from datastore and memcache) all entities of type src that matches q. // src must be a pointer to a struct type. func DelQuery(c PersistenceContext, src interface{}, q *datastore.Query) (err error) { var dataIds []*datastore.Key results := reflect.New(reflect.SliceOf(reflect.TypeOf(src).Elem())) dataIds, err = q.GetAll(c, results.Interface()) if err = FilterOkErrors(err); err != nil { return } memcacheKeys := []string{} var el reflect.Value resultsSlice := results.Elem() for index, dataId := range dataIds { el = resultsSlice.Index(index) var k key.Key if k, err = gaekey.FromGAE(dataId); err != nil { return } el.FieldByName("Id").Set(reflect.ValueOf(k)) if _, err = MemcacheKeys(c, el.Addr().Interface(), &memcacheKeys); err != nil { return } if err = runProcess(c, el.Addr().Interface(), BeforeDeleteName, nil); err != nil { return } } if err = datastore.DeleteMulti(c, dataIds); err != nil { return } for index, _ := range dataIds { el = resultsSlice.Index(index) if err = runProcess(c, el.Addr().Interface(), AfterDeleteName, nil); err != nil { return } } return memcache.Del(c, memcacheKeys...) }
func MemcacheDel(c PersistenceContext, model interface{}) (err error) { var keys []string if keys, err = MemcacheKeys(c, model, nil); err != nil { return } return memcache.Del(c, keys...) }
func (self *Mutex) Unlock(c gaecontext.GAEContext) (err error) { if err = datastore.Delete(c, lockIdForName(c, self.Name)); err != nil { return } err = memcache.Del(c, lockKeyForName(self.Name)) return }
func testMemcacheBasics(c gaecontext.HTTPContext) { if err := memcache.Del(c, "s"); err != nil { panic(err) } s := "" if _, err := memcache.Get(c, "s", &s); err != nil { panic(err) } if s != "" { panic(fmt.Errorf("Wrong value")) } if success, err := memcache.CAS(c, "s", "x", "y"); err != nil { panic(err) } else if success { panic(fmt.Errorf("Shouldn't succeed")) } s = "x" if err := memcache.Put(c, "s", s); err != nil { panic(err) } s2 := "" if _, err := memcache.Get(c, "s", &s2); err != nil { panic(err) } if s2 != "x" { panic(fmt.Errorf("Wrong value")) } if success, err := memcache.CAS(c, "s", "z", "y"); err != nil { panic(err) } else if success { panic(fmt.Errorf("Shouldn't succeed")) } if success, err := memcache.CAS(c, "s", "x", "y"); err != nil { panic(err) } else if !success { panic(fmt.Errorf("Should have succeeded")) } s3 := "" if _, err := memcache.Get(c, "s", &s3); err != nil { panic(err) } if s3 != "y" { panic(fmt.Errorf("Wrong value")) } }
/* Del will delete src from datastore and invalidate it from memcache. It will also load any old entities with the same id from datastore and run Before/AfterDelete on them */ func Del(c PersistenceContext, src interface{}) (err error) { var typ reflect.Type var id key.Key if typ, id, err = getTypeAndId(src); err != nil { return } if id == "" { err = errors.Errorf("%+v doesn't have an Id", src) return } gaeKey := gaekey.ToGAE(c, id) if !gaeKey.Incomplete() { old := reflect.New(typ) old.Elem().FieldByName(idFieldName).Set(reflect.ValueOf(id)) err = GetById(c, old.Interface()) if _, ok := err.(ErrNoSuchEntity); ok { err = nil } else if err == nil { if err = runProcess(c, old.Interface(), BeforeDeleteName, nil); err != nil { return } if err = datastore.Delete(c, gaeKey); err != nil { return } memKeys := []string{} if memKeys, err = MemcacheKeys(c, old.Interface(), nil); err != nil { return } if err = memcache.Del(c, memKeys...); err != nil { return } } if err = runProcess(c, old.Interface(), AfterDeleteName, nil); err != nil { return } } return }
/* Put will save src in datastore, invalidating cache and running hooks. This requires the loading of any old versions currently in the datastore, which will cause some extra work. */ func Put(c PersistenceContext, src interface{}) (err error) { var id key.Key if _, id, err = getTypeAndId(src); err != nil { return } if id == "" { err = errors.Errorf("%+v doesn't have an Id", src) return } gaeKey := gaekey.ToGAE(c, id) memcacheKeys := []string{} var oldIf interface{} if !gaeKey.Incomplete() { old := reflect.New(reflect.TypeOf(src).Elem()) old.Elem().FieldByName(idFieldName).Set(reflect.ValueOf(id)) err = GetById(c, old.Interface()) if _, ok := err.(ErrNoSuchEntity); ok { err = nil } else if err == nil { oldIf = old.Interface() if _, err = MemcacheKeys(c, oldIf, &memcacheKeys); err != nil { return } } else { return } } if oldIf == nil { if err = runProcess(c, src, BeforeCreateName, nil); err != nil { return } } else { if err = runProcess(c, src, BeforeUpdateName, oldIf); err != nil { return } } if err = runProcess(c, src, BeforeSaveName, oldIf); err != nil { return } if err = runProcess(c, src, ValidateName, nil); err != nil { return } if id, err = gaekey.FromGAErr(datastore.Put(c, gaeKey, src)); err != nil { return } reflect.ValueOf(src).Elem().FieldByName(idFieldName).Set(reflect.ValueOf(id)) if _, err = MemcacheKeys(c, src, &memcacheKeys); err != nil { return } if err = memcache.Del(c, memcacheKeys...); err != nil { return } if oldIf == nil { if err = runProcess(c, src, AfterCreateName, nil); err != nil { return } } else { if err = runProcess(c, src, AfterUpdateName, oldIf); err != nil { return } } return runProcess(c, src, AfterSaveName, oldIf) }
/* PutMulti will save src in datastore, invalidating cache and running hooks. This requires the loading of any old versions currently in the datastore, which will cause some extra work. */ func PutMulti(c PersistenceContext, src interface{}) (err error) { // validate srcVal := reflect.ValueOf(src) if srcVal.Kind() != reflect.Slice { err = errors.Errorf("%+v is not a slice", src) return } if srcVal.Type().Elem().Kind() != reflect.Ptr { err = errors.Errorf("%+v is not a slice of pointers", src) return } if srcVal.Type().Elem().Elem().Kind() != reflect.Struct { err = errors.Errorf("%+v is not a slice of struct pointers", src) return } // build required data for loading old entities gaeKeys := make([]*datastore.Key, srcVal.Len()) ids := make([]key.Key, srcVal.Len()) keysToLoad := []*datastore.Key{} indexMapping := []int{} for i := 0; i < srcVal.Len(); i++ { var id key.Key if _, id, err = getTypeAndId(srcVal.Index(i).Interface()); err != nil { return } if id == "" { err = errors.Errorf("%+v doesn't have an id", srcVal.Index(i)) return } ids[i] = id gaeKey := gaekey.ToGAE(c, id) gaeKeys[i] = gaeKey if !gaeKey.Incomplete() { keysToLoad = append(keysToLoad, gaeKey) indexMapping = append(indexMapping, i) } } // load old entities memcacheKeys := []string{} oldIfs := make([]interface{}, srcVal.Len()) if len(keysToLoad) > 0 { oldEntities := reflect.MakeSlice(reflect.SliceOf(srcVal.Type().Elem().Elem()), len(keysToLoad), len(keysToLoad)) getErr := datastore.GetMulti(c, keysToLoad, oldEntities.Interface()) // check which entities weren't in the database notFound := make([]bool, len(keysToLoad)) if getErr != nil { if multiErr, ok := getErr.(appengine.MultiError); ok { for index, e := range multiErr { if e == datastore.ErrNoSuchEntity { notFound[index] = true } else { err = e return } } } else { err = getErr return } } // put entities inside oldIfs, run AfterLoad, add memcache keys from the old entities for index, _ := range keysToLoad { if !notFound[index] { if idField := oldEntities.Index(index).FieldByName(idFieldName); idField.IsValid() { idField.Set(reflect.ValueOf(ids[indexMapping[index]])) } oldIf := oldEntities.Index(index).Addr().Interface() oldIfs[indexMapping[index]] = oldIf if err = runProcess(c, oldIf, AfterLoadName, nil); err != nil { return } if _, err = MemcacheKeys(c, oldIf, &memcacheKeys); err != nil { return } } } } // run the before hooks for i := 0; i < srcVal.Len(); i++ { if oldIfs[i] == nil { if err = runProcess(c, srcVal.Index(i).Interface(), BeforeCreateName, nil); err != nil { return } } else { if err = runProcess(c, srcVal.Index(i).Interface(), BeforeUpdateName, oldIfs[i]); err != nil { return } } if err = runProcess(c, srcVal.Index(i).Interface(), BeforeSaveName, oldIfs[i]); err != nil { return } if err = runProcess(c, srcVal.Index(i).Interface(), ValidateName, nil); err != nil { return } } // actually save if gaeKeys, err = datastore.PutMulti(c, gaeKeys, src); err != nil { return } // set ids and add memcache keys from the new entities for i := 0; i < srcVal.Len(); i++ { if ids[i], err = gaekey.FromGAE(gaeKeys[i]); err != nil { return } srcVal.Index(i).Elem().FieldByName(idFieldName).Set(reflect.ValueOf(ids[i])) if _, err = MemcacheKeys(c, srcVal.Index(i).Interface(), &memcacheKeys); err != nil { return } } // clear memcache if err = memcache.Del(c, memcacheKeys...); err != nil { return } // run the after hooks for i := 0; i < srcVal.Len(); i++ { if oldIfs[i] == nil { if err = runProcess(c, srcVal.Index(i).Interface(), AfterCreateName, nil); err != nil { return } } else { if err = runProcess(c, srcVal.Index(i).Interface(), AfterUpdateName, oldIfs[i]); err != nil { return } } if err = runProcess(c, srcVal.Index(i).Interface(), AfterSaveName, oldIfs[i]); err != nil { return } } return }