// Should store the given user, after encrypting its password func TestStoreUser(t *testing.T) { ctx, done, err := aetest.NewContext() if err != nil { t.Fatal(err) } defer done() user := &models.User{Username: "******", FirstName: "Tim", Email: "*****@*****.**", Password: []byte("I <3 golang")} err = repositories.StoreUser(ctx, user) if err != nil { t.Fatal(err) } key := datastore.NewKey(ctx, "User", "testertim", 0, nil) var storedUser models.User err = datastore.Get(ctx, key, &storedUser) if err != nil { t.Fatal(err) } if storedUser.FirstName != user.FirstName { t.Errorf("FirstName %d, want %d", storedUser.FirstName, user.FirstName) } if storedUser.Username != "" { t.Errorf("Username %d should be derived from the key, not stored", storedUser.Username) } if string(storedUser.Password) == "I <3 golang" { t.Errorf("Password %d should be hashed and not %d", string(storedUser.Password), "I <3 golang") } }
func GetCompanyByUser(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var u model.User if err := datastore.Get(ctx, p.User, &u); err != nil { return http.StatusInternalServerError, nil } if u.Company == nil { return http.StatusUnauthorized, nil } // The account is associated with a company, so we return it. var company model.Company if err := datastore.Get(ctx, u.Company, &company); err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(company.Key(u.Company)) return http.StatusOK, nil }
// Increment increments the named counter. func Increment(ctx context.Context, name string) error { // Get counter config. var cfg counterConfig ckey := datastore.NewKey(ctx, configKind, name, 0, nil) err := datastore.RunInTransaction(ctx, func(ctx context.Context) error { err := datastore.Get(ctx, ckey, &cfg) if err == datastore.ErrNoSuchEntity { cfg.Shards = defaultShards _, err = datastore.Put(ctx, ckey, &cfg) } return err }, nil) if err != nil { return err } var s shard err = datastore.RunInTransaction(ctx, func(ctx context.Context) error { shardName := fmt.Sprintf("%s-shard%d", name, rand.Intn(cfg.Shards)) key := datastore.NewKey(ctx, shardKind, shardName, 0, nil) err := datastore.Get(ctx, key, &s) // A missing entity and a present entity will both work. if err != nil && err != datastore.ErrNoSuchEntity { return err } s.Name = name s.Count++ _, err = datastore.Put(ctx, key, &s) return err }, nil) if err != nil { return err } memcache.IncrementExisting(ctx, memcacheKey(name), 1) return nil }
func viewStory(res http.ResponseWriter, req *http.Request, ps httprouter.Params) { ctx := appengine.NewContext(req) sd := sessionInfo(req) link := ps.ByName("story") title := strings.Replace(link, "-", " ", -1) //translate link to title owner := ps.ByName("owner") userkey := datastore.NewKey(ctx, "Users", owner, 0, nil) key := datastore.NewKey(ctx, "Stories", title, 0, userkey) //owner is ancestor - eliminates need for owner-story table var story Story err := datastore.Get(ctx, key, &story) if err != nil { panic(err) } var user User user.Username = owner err = datastore.Get(ctx, userkey, &user) if err != nil { panic(err) } sd.ViewingStory = story sd.ViewingUser = user tpl.ExecuteTemplate(res, "view.html", &sd) }
// Increment increments the named counter. func Increment(c context.Context, valName string) error { // Get counter config. shardsTotal := dsu.WrapInt{} dsu.McacheGet(c, mcKeyShardsTotal(valName), &shardsTotal) if shardsTotal.I < 1 { ckey := datastore.NewKey(c, dsKindNumShards, mcKeyShardsTotal(valName), 0, nil) errTx := datastore.RunInTransaction(c, func(c context.Context) error { err := datastore.Get(c, ckey, &shardsTotal) if err == datastore.ErrNoSuchEntity { shardsTotal.I = defaultNumShards _, err = datastore.Put(c, ckey, &shardsTotal) } return err }, nil) if errTx != nil { return errTx } dsu.McacheSet(c, mcKeyShardsTotal(valName), dsu.WrapInt{shardsTotal.I}) } // pick random counter and increment it errTx := datastore.RunInTransaction(c, func(c context.Context) error { shardId := rand.Intn(shardsTotal.I) dsKey := datastore.NewKey(c, dsKindShard, keySingleShard(valName, shardId), 0, nil) var sd WrapShardData err := datastore.Get(c, dsKey, &sd) // A missing entity and a present entity will both work. if err != nil && err != datastore.ErrNoSuchEntity { return err } sd.Name = valName sd.ShardId = shardId sd.I++ _, err = datastore.Put(c, dsKey, &sd) if ll > 2 { aelog.Infof(c, "ds put %v %v", dsKey, sd) } return err }, nil) if errTx != nil { return errTx } memcache.Increment(c, mcKey(valName), 1, 0) // collect number of updates // per valName per instance in memory // for every interval of 10 minutes // // a batch job checks if the number of shards should be increased or decreased // and truncates this map updateSamplingFrequency[valName+util.TimeMarker()[:len("2006-01-02 15:0")]] += 1 return nil }
// Load - Takes a datastore.Key provided and loads it into the current Ticket object func (t *Ticket) Load(ctx context.Context, k datastore.Key) error { err := datastore.Get(ctx, &k, t) t.DatastoreKey = k t.EventKey = k.Parent() if err = datastore.Get(ctx, &k, t); err != nil { return err } return nil }
func TestDatastoreFixture(t *testing.T) { filepath := mkTempfile(`[{ "_kind": "FixtureKind", "_key": "key1", "IntValue": 10, "FloatValue": 2.4, "BoolValue": true, "StringValue": "foobar", "BytesValue": "[]bytesfoobar", "DateTimeValue": "2014-01-02T14:02:50Z", "DateValue": "2014-01-02", "Slice": ["a", "b", "c"], "Struct": { "Foo": "bar" } },{ "_kind": "FixtureKind", "_key": "key1", "_ns": "ns1", "StringValue": "withns1" } ]`) assert := wcg.NewAssert(t) var fk FixtureKind assert.Nil(DatastoreFixture(ts.Context, filepath, nil), "DatastoreFixture") key := datastore.NewKey(ts.Context, "FixtureKind", "key1", 0, nil) wcg.NewLogger(nil).Infof("GET: %s", key) assert.Nil(datastore.Get(ts.Context, key, &fk), "datastore.Get('key1') ") assert.EqInt(10, fk.IntValue, "IntValue should be 10") assert.EqFloat32(2.4, fk.FloatValue, "FloatValue should be 2.4") assert.EqStr("foobar", fk.StringValue, "StringValue should be 'foobar'") assert.EqStr("bytesfoobar", string(fk.BytesValue), "BytesValue should be 'foobar'") assert.EqInt(3, len(fk.Slice), "len(Slice) should be 3") assert.EqStr("a", string(fk.Slice[0]), "Slice[0] should be 'a'") assert.EqStr("b", string(fk.Slice[1]), "Slice[0] should be 'a'") assert.EqStr("c", string(fk.Slice[2]), "Slice[0] should be 'a'") assert.EqTime(time.Date(2014, 01, 02, 14, 02, 50, 0, time.UTC), fk.DateTimeValue, "DateTimeValue should be 2014-01-02T14:02:50Z") assert.EqTime(time.Date(2014, 01, 02, 0, 0, 0, 0, time.UTC), fk.DateValue, "DateTimeValue should be 2014-01-02T00:00:00Z") assert.EqStr("bar", string(fk.Struct.Foo), "Struct.Foo should be 'bar'") // namespace ns1, _ := appengine.Namespace(ts.Context, "ns1") key = datastore.NewKey(ns1, "FixtureKind", "key1", 0, nil) assert.Nil(datastore.Get(ns1, key, &fk), "datastore.Get('key1') /w ns1") assert.EqStr("withns1", fk.StringValue, "StringValue should be 'withns1'") }
//LoadAccess loads access data by token func (s *AEStorage) LoadAccess(c context.Context, code string) (*osin.AccessData, error) { log.Infof(c, "Access code: %s", code) key := datastore.NewKey(c, AccessDataKind, code, 0, nil) var token AccessDataModel err := datastore.Get(c, key, &token) if err != nil { return nil, errors.New("Access not found") } var rtoken = token.ToAccessData() client, err := s.GetClient(c, token.ClientID) if client == nil || err != nil { return nil, errors.New("Client not found") } rtoken.Client = client if token.AuthorizationCode != "" { auth, err := s.LoadAuthorize(c, token.AuthorizationCode) if auth == nil || err != nil { return nil, errors.New("Authorization not found") } rtoken.AuthorizeData = auth } return rtoken, nil }
func (s *TaskService) ByID(ctx context.Context, id string) (*Task, error) { rootKey := datastore.NewKey(ctx, "Root", "root", 0, nil) k := datastore.NewKey(ctx, "Task", id, 0, rootKey) ct, ok := CacheFromContext(ctx).Get(k).(*Task) if ok { return ct, nil } span := trace.FromContext(ctx).NewChild("trythings.task.ByID") defer span.Finish() var t Task err := datastore.Get(ctx, k, &t) if err != nil { return nil, err } ok, err = s.IsVisible(ctx, &t) if err != nil { return nil, err } if !ok { return nil, errors.New("cannot access task") } CacheFromContext(ctx).Set(k, &t) return &t, nil }
func (s *ViewService) ByID(ctx context.Context, id string) (*View, error) { rootKey := datastore.NewKey(ctx, "Root", "root", 0, nil) k := datastore.NewKey(ctx, "View", id, 0, rootKey) cv, ok := CacheFromContext(ctx).Get(k).(*View) if ok { return cv, nil } span := trace.FromContext(ctx).NewChild("trythings.view.ByID") defer span.Finish() var v View err := datastore.Get(ctx, k, &v) if err != nil { return nil, err } ok, err = s.IsVisible(ctx, &v) if err != nil { return nil, err } if !ok { return nil, errors.New("cannot access view") } CacheFromContext(ctx).Set(k, &v) return &v, nil }
func showUser(res http.ResponseWriter, req *http.Request) { ctx := appengine.NewContext(req) u := user.Current(ctx) email := u.Email key := datastore.NewKey(ctx, "User", email, 0, nil) var entity User err := datastore.Get(ctx, key, &entity) if err == datastore.ErrNoSuchEntity { http.NotFound(res, req) return } else if err != nil { http.Error(res, err.Error(), 500) return } log.Infof(ctx, "%v", entity) res.Header().Set("Content-Type", "text/html") fmt.Fprintln(res, ` <dl> <dt>`+entity.FirstName+`</dt> <dd>`+entity.LastName+`</dd> <dd>`+u.Email+`</dd> </dl> `) }
func Tasks(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var u model.User if err = datastore.Get(ctx, p.User, &u); err != nil { return http.StatusInternalServerError, err } // User is a coder if u.Company == nil { return http.StatusUnauthorized, nil } switch r.Method { case "GET": return getAllTasks(ctx, w, r) case "POST": return createTask(ctx, w, r) default: return http.StatusMethodNotAllowed, nil } }
func handlePersonalPage(res http.ResponseWriter, req *http.Request) { ctx := appengine.NewContext(req) session := getSession(ctx, req) username := strings.SplitN(req.URL.Path, "/", 3)[2] if username == "" { http.Redirect(res, req, "/userslist", 302) return } q := datastore.NewQuery("Image").Filter("Username ="******"List", username, 0, nil) var list List datastore.Get(ctx, key, &list) listItems := make([]string, 0) if strings.TrimSpace(list.List) != "" { listItems = strings.Split(list.List, "\n") } model := &personalModel{ Session: session, Username: username, ListItems: listItems, Images: images, } err := tpls.ExecuteTemplate(res, "personalpage", model) if err != nil { http.Error(res, err.Error(), 500) return } }
func (s *UserService) ByID(ctx context.Context, id string) (*User, error) { rootKey := datastore.NewKey(ctx, "Root", "root", 0, nil) k := datastore.NewKey(ctx, "User", id, 0, rootKey) cu, ok := CacheFromContext(ctx).Get(k).(*User) if ok { return cu, nil } var u User err := datastore.Get(ctx, k, &u) if err != nil { return nil, err } ok, err = s.IsVisible(ctx, &u) if err != nil { return nil, err } if !ok { return nil, errors.New("cannot access user") } CacheFromContext(ctx).Set(k, &u) return &u, nil }
func createFinalResult(ctx context.Context, w http.ResponseWriter, result model.KeyedResult) (int, error) { var challenge model.Challenge if err := datastore.Get(ctx, result.Challenge, &challenge); err != nil { return http.StatusInternalServerError, nil } result.Finished = time.Now() for i, taskKey := range challenge.Tasks { key, err := getLatestSubmissionKey(ctx, result.Key, taskKey) if err != nil { return http.StatusInternalServerError, err } result.FinalSubmissions[i] = key } _, err := result.Put(ctx, result.Key) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(result) go computeFinalScore(ctx, result, challenge) return http.StatusOK, nil }
func handleListForm(res http.ResponseWriter, req *http.Request) { ctx := appengine.NewContext(req) session := getSession(ctx, req) username := session.Username if username == "" { http.Redirect(res, req, "/loginform", 302) return } list := &List{ Username: username, } key := datastore.NewKey(ctx, "List", username, 0, nil) datastore.Get(ctx, key, list) if req.Method == "POST" { list.List = req.FormValue("list") _, err := datastore.Put(ctx, key, list) if err != nil { http.Error(res, err.Error(), 500) return } http.Redirect(res, req, "/user/"+username, 302) return } model := &listModel{ Session: session, List: list.List, } err := tpls.ExecuteTemplate(res, "listform", model) if err != nil { http.Error(res, err.Error(), 500) return } }
// linkHandler services requests to short URLs. // http://golang.org/s/key // It consults memcache and datastore for the Link for key. // It then sends a redirects or an error message. func linkHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) key := r.URL.Path[len(prefix)+1:] if !validKey.MatchString(key) { http.Error(w, "not found", http.StatusNotFound) return } var link Link _, err := memcache.JSON.Get(c, cacheKey(key), &link) if err != nil { k := datastore.NewKey(c, kind, key, 0, nil) err = datastore.Get(c, k, &link) switch err { case datastore.ErrNoSuchEntity: http.Error(w, "not found", http.StatusNotFound) return default: // != nil log.Errorf(c, "%q: %v", key, err) http.Error(w, "internal server error", http.StatusInternalServerError) return case nil: item := &memcache.Item{ Key: cacheKey(key), Object: &link, } if err := memcache.JSON.Set(c, item); err != nil { log.Warningf(c, "%q: %v", key, err) } } } http.Redirect(w, r, link.Target, http.StatusFound) }
// create snapshot func (a *MinecraftCronApi) createSnapshot(ctx context.Context, ds *compute.DisksService, world string) error { sn := fmt.Sprintf("minecraft-world-%s-%s", world, time.Now().Format("20060102-150405")) log.Infof(ctx, "create snapshot %s", sn) var minecraft Minecraft key := datastore.NewKey(ctx, "Minecraft", world, 0, nil) err := datastore.Get(ctx, key, &minecraft) if err == datastore.ErrNoSuchEntity { log.Infof(ctx, "Minecraft Entity Not Found. world = %s", world) return nil } if err != nil { return nil } minecraft.Key = key s := &compute.Snapshot{ Name: sn, } disk := fmt.Sprintf("minecraft-world-%s", world) ope, err := ds.CreateSnapshot(PROJECT_NAME, minecraft.Zone, disk, s).Do() if err != nil { log.Errorf(ctx, "ERROR insert snapshot: %s", err) return err } WriteLog(ctx, "INSTNCE_SNAPSHOT_OPE", ope) tq := ServerTQApi{} _, err = tq.CallDeleteInstance(ctx, minecraft.Key, ope.Name, sn) return err }
func (a *MinecraftCronApi) deleteInstance(ctx context.Context, is *compute.InstancesService, world string) <-chan error { log.Infof(ctx, "Delete Instance Target World Name = %s", world) receiver := make(chan error) go func() { var minecraft Minecraft key := datastore.NewKey(ctx, "Minecraft", world, 0, nil) err := datastore.Get(ctx, key, &minecraft) if err == datastore.ErrNoSuchEntity { log.Infof(ctx, "Minecraft Entity Not Found. world = %s", world) receiver <- nil return } if err != nil { receiver <- nil return } minecraft.Key = key _, err = deleteInstance(ctx, is, minecraft) receiver <- err }() return receiver }
func (s *SpaceService) ByID(ctx context.Context, id string) (*Space, error) { rootKey := datastore.NewKey(ctx, "Root", "root", 0, nil) k := datastore.NewKey(ctx, "Space", id, 0, rootKey) csp, ok := CacheFromContext(ctx).Get(k).(*Space) if ok { return csp, nil } span := trace.FromContext(ctx).NewChild("trythings.space.ByID") defer span.Finish() var sp Space err := datastore.Get(ctx, k, &sp) if err != nil { return nil, err } ok, err = s.IsVisible(ctx, &sp) if err != nil { return nil, err } if !ok { return nil, errors.New("cannot access space") } CacheFromContext(ctx).Set(k, &sp) return &sp, nil }
func TestBasicUsage2(t *testing.T) { c, closer, err := aetest.NewContext() if err != nil { t.Fatal(err) } defer closer() src := &a.Sample{"Foo!"} key := datastore.NewIncompleteKey(c, "Sample", nil) _, err = datastore.Put(c, key, src) if err != nil { t.Fatal(err) } builder := a.NewSampleQueryBuilder() builder.Foo.GreaterThan("Foo").KeysOnly().Limit(3) iter := builder.Query().Run(c) for { key, err = iter.Next(nil) if err == datastore.Done { break } else if err != nil { t.Fatal(err) } src := &a.Sample{} err = datastore.Get(c, key, src) if err != nil { t.Fatal(err) } t.Logf("key: %#v, entity: %#v", key, src) } }
func handle(res http.ResponseWriter, req *http.Request) { if req.URL.Path != "/" { http.NotFound(res, req) return } ctx := appengine.NewContext(req) u := user.Current(ctx) key := datastore.NewKey(ctx, "Profile", u.Email, 0, nil) var profile Profile err := datastore.Get(ctx, key, &profile) if err == datastore.ErrNoSuchEntity { http.Redirect(res, req, "/createProfile", http.StatusSeeOther) return } else if err != nil { http.Error(res, "Server Error", http.StatusInternalServerError) log.Errorf(ctx, err.Error()) return } tpl, err := template.ParseFiles("viewProfile.gohtml") if err != nil { http.Error(res, "Server Error", http.StatusInternalServerError) log.Errorf(ctx, err.Error()) return } err = tpl.Execute(res, &profile) if err != nil { http.Error(res, "Server Error", http.StatusInternalServerError) log.Errorf(ctx, err.Error()) return } }
func handleResolve(w http.ResponseWriter, r *http.Request, apiKey APIKey) *appError { if r.Method != "GET" { return &appError{nil, fmt.Sprintf("Invalid request method: %s", r.Method), 401} } reqPath := r.FormValue("path") if reqPath == "" { return &appError{nil, "The `path` parameter is required. ", 401} } c := appengine.NewContext(r) linkResult, err := getMatchingLinkChatString(c, r.FormValue("chatID"), reqPath) var resp *ResolveResponse if err != nil { resp = &ResolveResponse{false, nil, nil, "Not Found"} } else { var resultChat Chat if linkResult.ChatKey != nil { err = datastore.Get(c, linkResult.ChatKey, &resultChat) } resp = &ResolveResponse{true, linkResult, &resultChat, ""} } respJSON, _ := json.Marshal(resp) w.Write(respJSON) return nil }
// ChallengeByKey loads a challenge by key. func ChallengeByKey(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if r.Method != "GET" { return http.StatusMethodNotAllowed, nil } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } key, err := datastore.DecodeKey(mux.Vars(r)["key"]) if err != nil { return http.StatusInternalServerError, err } var challenge model.Challenge err = datastore.Get(ctx, key, &challenge) if err != nil { return http.StatusInternalServerError, err } e := json.NewEncoder(w) if parent := p.UserKey.Parent(); parent == nil { // The current user is a coder so we must also create a result. e.Encode(challenge.Key(key)) } else { // TODO(pbochis): If a company representativemakes the request // we also include Tasks in the response. e.Encode(challenge.Key(key)) } return http.StatusOK, nil }
func Get(c context.Context, key, def string, values ...interface{}) string { configLock.Lock() defer configLock.Unlock() val, ok := configCache[key] if ok { return fmt.Sprintf(val, values...) } value := Value{} dskey := datastore.NewKey(c, ConfigName, key, 0, nil) err := datastore.Get(c, dskey, &value) if err == datastore.ErrNoSuchEntity { value.Val = def log.Infof(c, "Creating default config for key - %s - default value is - %s", key, value.Val) _, err = datastore.Put(c, dskey, &value) if err != nil { log.Errorf(c, "Error creating default config for key - %s - error is - %v", key, err) } return fmt.Sprintf(def, values...) // return default, totally new config setting } if err != nil { log.Errorf(c, "Error fetching config for key - %s - error is - %v", key, err) return def // error, return the default } configCache[key] = value.Val return fmt.Sprintf(value.Val, values...) }
func findPlayer(c context.Context, key *datastore.Key) (*PlayerData, error) { data := new(PlayerData) if err := datastore.Get(c, key, data); err != nil { return new(PlayerData), err } return data, nil }
func newPlayer(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) id := r.FormValue("id") if id == "" { http.Error(w, "need a non-blank id from the form data", http.StatusBadRequest) return } k := datastore.NewKey(ctx, "Player", id, 0, nil) err := datastore.RunInTransaction(ctx, func(ctx context.Context) error { var p *Player if err := datastore.Get(ctx, k, p); err != datastore.ErrNoSuchEntity { return codeErr{fmt.Errorf("player(%s) already exists", id), http.StatusConflict} } // TODO(jaguilar): Add another system. Add a system Registry. Leagues // can have ratings. p = &Player{Rating: eloSys.InitialRating(), key: k} if _, err := datastore.Put(ctx, p.key, p); err != nil { return err } return nil }, nil) if err != nil { httpError(w, err) return } fmt.Fprintf( w, `<html><head><meta http-equiv="refresh" content="5,/"></head> <body>Successfully added %s. Redirecting you in five seconds.</body></html>`, id) }
func getSoldCounter(c context.Context) int { var cachedCounter int _, err := memcache.JSON.Get(c, "sold", &cachedCounter) if err == nil { log.Infof(c, "[counter] Cache hit") return cachedCounter } if err != memcache.ErrCacheMiss { log.Infof(c, "[counter] Unexpected error") web.LogError(c, err, "Error accessing counter in memcache") } else { log.Infof(c, "[counter] Cache miss") } sold := new(Counter) key := datastore.NewKey(c, "Counter", "sold", 0, nil) err = datastore.Get(c, key, sold) if err != nil && err != datastore.ErrNoSuchEntity { web.LogError(c, err, "Error reading counter from datastore") return 0 } err = memcache.JSON.Set(c, &memcache.Item{ Key: "sold", Object: &sold.Value, }) if err != nil { web.LogError(c, err, "Error storing counter in memcache") } return sold.Value }
func deleteData(res http.ResponseWriter, req *http.Request) { ctx := appengine.NewContext(req) u := user.Current(ctx) keyVal := req.FormValue("keyVal") key, err := datastore.DecodeKey(keyVal) if err != nil { http.Error(res, "Invalid data", http.StatusBadRequest) log.Warningf(ctx, err.Error()) return } var l list err = datastore.Get(ctx, key, &l) if err != nil { http.Error(res, "Invalid data", http.StatusBadRequest) log.Warningf(ctx, err.Error()) return } if l.Owner != u.Email { http.Error(res, "Not authorized to delete this entry", http.StatusUnauthorized) log.Warningf(ctx, err.Error()) return } err = datastore.Delete(ctx, key) if err != nil { http.Error(res, "Server Error", http.StatusInternalServerError) log.Errorf(ctx, err.Error()) return } }
func incrementSoldCounter(c context.Context) error { _, err := memcache.IncrementExisting(c, "sold", 1) if err != nil { if err == datastore.ErrNoSuchEntity { log.Infof(c, "[counter] Cache miss when incrementing") } else { return err } } sold := new(Counter) err = datastore.RunInTransaction(c, func(c context.Context) error { key := datastore.NewKey(c, "Counter", "sold", 0, nil) err := datastore.Get(c, key, sold) if err != nil && err != datastore.ErrNoSuchEntity { return err } sold.Value++ _, err = datastore.Put(c, key, sold) if err != nil { sold.Value-- return err } return nil }, nil) return err }