Example #1
0
// 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...)
}
Example #2
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 #3
0
func GetQuery(c PersistenceContext, src interface{}, q *datastore.Query) (err error) {
	srcTyp := reflect.TypeOf(src)
	if srcTyp.Kind() != reflect.Ptr {
		err = errors.Errorf("%+v is not a pointer", src)
		return
	}
	if srcTyp.Elem().Kind() != reflect.Slice {
		err = errors.Errorf("%+v is not a pointer to a slice", src)
		return
	}
	if srcTyp.Elem().Elem().Kind() == reflect.Ptr {
		if srcTyp.Elem().Elem().Elem().Kind() != reflect.Struct {
			err = errors.Errorf("%+v is not a pointer to a slice of struct pointers", src)
			return
		}
	} else if srcTyp.Elem().Elem().Kind() != reflect.Struct {
		err = errors.Errorf("%+v is not a pointer to a slice of structs", src)
		return
	}
	var dataIds []*datastore.Key
	dataIds, err = q.GetAll(c, src)
	if err = FilterOkErrors(err); err != nil {
		return
	}
	srcVal := reflect.ValueOf(src)
	for index, dataId := range dataIds {
		el := srcVal.Elem().Index(index)
		var k key.Key
		if k, err = gaekey.FromGAE(dataId); err != nil {
			return
		}
		if el.Kind() == reflect.Ptr {
			el.Elem().FieldByName("Id").Set(reflect.ValueOf(k))
			if err = runProcess(c, el.Interface(), AfterLoadName, nil); err != nil {
				return
			}
		} else {
			el.FieldByName("Id").Set(reflect.ValueOf(k))
			if err = runProcess(c, el.Addr().Interface(), AfterLoadName, nil); err != nil {
				return
			}
		}
	}
	return
}
Example #4
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
}