/* GetById will find memoize finding dst in the datastore, setting its id and running its AfterLoad function, if any. */ func GetById(c PersistenceContext, dst interface{}) (err error) { k, err := keyById(dst) if err != nil { return } val := reflect.ValueOf(dst).Elem() // we need to clear this crap, because datastore.Get does NOT overwrite all fields - it APPENDS to some of them (notably slices) // which will create a shitstorm if we try to reload an object we already have, that includes slices, in that it will append // all datastore values to the current slice instead of resetting the slice to what is in datastore clear(c, val) if err = memcache.Memoize(c, k, dst, func() (result interface{}, err error) { err = findById(c, dst) if _, ok := err.(ErrNoSuchEntity); ok { err = memcache.ErrCacheMiss } if err != nil { return } result = dst return }); err == nil { err = runProcess(c, dst, AfterLoadName, nil) } else if err == memcache.ErrCacheMiss { err = newErrNoSuchEntity(dst, datastore.ErrNoSuchEntity) } return }
// see AncestorFinder func (self finder) countWithAncestor(c PersistenceContext, ancestor key.Key, values ...interface{}) (result int, err error) { if len(values) != len(self.fields) { err = errors.Errorf("%+v does not match %+v", values, self.fields) return } // We can't really cache finders that don't use ancestor fields, since they are eventually consistent which might fill the cache with inconsistent data if ancestor == "" { if result, err = self.getCount(c, "", values); err != nil { return } } else { count := &countResult{} if err = memcache.Memoize(c, self.keyForValues(ancestor, values), count, func() (result interface{}, err error) { var num int if num, err = self.getCount(c, ancestor, values); err == nil { result = &countResult{ Count: num, } } return }); err != nil { return } result = count.Count } return }
// see AncestorFinder func (self finder) getWithAncestor(c PersistenceContext, dst interface{}, ancestor key.Key, values ...interface{}) (err error) { if len(values) != len(self.fields) { wantedTypeNames := []string{} for _, field := range self.fields { wantedTypeNames = append(wantedTypeNames, field.Type.Name()) } givenTypeNames := []string{} for _, val := range values { givenTypeNames = append(givenTypeNames, reflect.TypeOf(val).Name()) } err = errors.Errorf("Finder wants %+v as arguments, but got %+v", wantedTypeNames, givenTypeNames) return } // We can't really cache finders that don't use ancestor fields, since they are eventually consistent which might fill the cache with inconsistent data if ancestor == "" { if err = self.find(c, dst, "", values); err != nil { return } } else { if err = memcache.Memoize(c, self.keyForValues(ancestor, values), dst, func() (result interface{}, err error) { if err = self.find(c, dst, ancestor, values); err == nil { result = dst } return }); err != nil { return } } val := reflect.ValueOf(dst).Elem() errors := appengine.MultiError{} for i := 0; i < val.Len(); i++ { el := val.Index(i) if err = runProcess(c, el.Addr().Interface(), AfterLoadName, nil); err != nil { errors = append(errors, err) } } if len(errors) > 0 { err = errors } return }