// 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 }
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 }
// 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 }
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 }
/* 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 }