Example #1
0
// find runs a datastore query, if ancestor != nil an ancestor query, and sets the id of all found models.
func (self finder) find(c PersistenceContext, dst interface{}, ancestor key.Key, values []interface{}) (err error) {
	q := datastore.NewQuery(reflect.TypeOf(self.model).Elem().Name())
	if ancestor != "" {
		q = q.Ancestor(gaekey.ToGAE(c, ancestor))
	}
	for index, value := range values {
		q = q.Filter(fmt.Sprintf("%v=", self.fields[index].Name), value)
	}
	var ids []*datastore.Key
	ids, err = q.GetAll(c, dst)
	if err = FilterOkErrors(err); err != nil {
		return
	}
	dstElem := reflect.ValueOf(dst).Elem()
	var element reflect.Value
	for index, id := range ids {
		element = dstElem.Index(index)
		if element.Kind() == reflect.Ptr {
			element = element.Elem()
		}
		var k key.Key
		if k, err = gaekey.FromGAE(id); err != nil {
			return
		}
		element.FieldByName(idFieldName).Set(reflect.ValueOf(k))
	}
	return
}
Example #2
0
func GetMulti(c PersistenceContext, ids []key.Key, src interface{}) (err error) {
	dsIds := make([]*datastore.Key, len(ids))
	for index, id := range ids {
		dsIds[index] = gaekey.ToGAE(c, id)
	}
	getErr := datastore.GetMulti(c, dsIds, src)
	merr, isMerr := getErr.(appengine.MultiError)
	if !isMerr && getErr != nil {
		err = getErr
		return
	}
	srcVal := reflect.ValueOf(src)
	for index, id := range ids {
		if !isMerr || merr[index] == nil {
			el := srcVal.Index(index)
			for el.Kind() == reflect.Ptr {
				el = el.Elem()
			}
			el.FieldByName("Id").Set(reflect.ValueOf(id))
			if err = runProcess(c, el.Addr().Interface(), AfterLoadName, nil); err != nil {
				return
			}
		}
	}
	if isMerr && merr != nil {
		err = merr
	}
	return
}
Example #3
0
// findById will find dst in the datastore and set its id.
func findById(c PersistenceContext, dst interface{}) (err error) {
	var id key.Key
	if _, id, err = getTypeAndId(dst); err != nil {
		return
	}
	if err = datastore.Get(c, gaekey.ToGAE(c, id), dst); err == datastore.ErrNoSuchEntity {
		err = newErrNoSuchEntity(dst, err)
		return
	}
	if err = FilterOkErrors(err); err != nil {
		return
	}
	return
}
Example #4
0
func (self finder) getCount(c PersistenceContext, ancestor key.Key, values []interface{}) (result int, err error) {
	q := datastore.NewQuery(reflect.TypeOf(self.model).Elem().Name())
	if ancestor != "" {
		q = q.Ancestor(gaekey.ToGAE(c, ancestor))
	}
	for index, value := range values {
		q = q.Filter(fmt.Sprintf("%v=", self.fields[index].Name), value)
	}
	result, err = q.Count(c)
	if err = FilterOkErrors(err); err != nil {
		return
	}
	return
}
Example #5
0
/*
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
}
Example #6
0
/*
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)
}
Example #7
0
/*
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
}