Beispiel #1
0
/*
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
}
Beispiel #2
0
// 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
}
Beispiel #3
0
// 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
}