From a6cd2a79612d6d96e0e929ab769ec5e70cd35f5f Mon Sep 17 00:00:00 2001 From: hmhealey Date: Wed, 7 Oct 2015 10:19:02 -0400 Subject: Moved saving multiple user preferences into a database transaction --- store/sql_preference_store.go | 112 +++++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 29 deletions(-) (limited to 'store/sql_preference_store.go') diff --git a/store/sql_preference_store.go b/store/sql_preference_store.go index 3e3a91f61..366a63fa6 100644 --- a/store/sql_preference_store.go +++ b/store/sql_preference_store.go @@ -39,53 +39,97 @@ func (s SqlPreferenceStore) Save(preference *model.Preference) StoreChannel { storeChannel := make(StoreChannel) go func() { - result := StoreResult{} + storeChannel <- s.save(s.GetMaster(), preference) + close(storeChannel) + }() - if result.Err = preference.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) - return - } + return storeChannel +} - if err := s.GetMaster().Insert(preference); err != nil { - if IsUniqueConstraintError(err.Error(), "UserId", "preferences_pkey") { - result.Err = model.NewAppError("SqlPreferenceStore.Save", "A preference with that user id, category, name, and alt id already exists", - "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error()) - } else { - result.Err = model.NewAppError("SqlPreferenceStore.Save", "We couldn't save the preference", - "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error()) - } +func (s SqlPreferenceStore) save(queryable Queryable, preference *model.Preference) StoreResult { + result := StoreResult{} + + if result.Err = preference.IsValid(); result.Err != nil { + return result + } + + if err := queryable.Insert(preference); err != nil { + if IsUniqueConstraintError(err.Error(), "UserId", "preferences_pkey") { + result.Err = model.NewAppError("SqlPreferenceStore.Save", "A preference with that user id, category, name, and alt id already exists", + "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error()) } else { - result.Data = preference + result.Err = model.NewAppError("SqlPreferenceStore.Save", "We couldn't save the preference", + "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error()) } + } else { + result.Data = preference + } - storeChannel <- result + return result +} + +func (s SqlPreferenceStore) Update(preference *model.Preference) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + storeChannel <- s.update(s.GetMaster(), preference) close(storeChannel) }() return storeChannel } -func (s SqlPreferenceStore) Update(preference *model.Preference) StoreChannel { +func (s SqlPreferenceStore) update(queryable Queryable, preference *model.Preference) StoreResult { + result := StoreResult{} + + if result.Err = preference.IsValid(); result.Err != nil { + return result + } + + if count, err := queryable.Update(preference); err != nil { + result.Err = model.NewAppError("SqlPreferenceStore.Update", "We couldn't update the preference", + "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error()) + } else { + result.Data = count + } + + return result +} + +func (s SqlPreferenceStore) SaveOrUpdate(preferences ...*model.Preference) StoreChannel { storeChannel := make(StoreChannel) go func() { result := StoreResult{} - if result.Err = preference.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) - return - } + db := s.GetReplica() - if count, err := s.GetMaster().Update(preference); err != nil { - result.Err = model.NewAppError("SqlPreferenceStore.Update", "We couldn't update the preference", - "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId+", "+err.Error()) - } else if count != 1 { - result.Err = model.NewAppError("SqlPreferenceStore.Update", "We couldn't update the preference", - "user_id="+preference.UserId+", category="+preference.Category+", name="+preference.Name+", alt_id="+preference.AltId) + if len(preferences) > 1 { + // wrap in a transaction so that if one fails, everything fails + transaction, err := db.Begin() + if err != nil { + result.Err = model.NewAppError("SqlPreferenceStore.SaveOrUpdateMultiple", "Unable to open transaction to update preferences", err.Error()) + } else { + for _, preference := range preferences { + if err := s.saveOrUpdate(transaction, preference); err != nil { + result.Err = err + break + } + } + + if result.Err == nil { + if err := transaction.Commit(); err != nil { + // don't need to rollback here since the transaction is already closed + result.Err = model.NewAppError("SqlPreferenceStore.SaveOrUpdateMultiple", "Unable to commit transaction to update preferences", err.Error()) + } + } else { + if err := transaction.Rollback(); err != nil { + result.Err = model.NewAppError("SqlPreferenceStore.SaveOrUpdateMultiple", "Unable to rollback transaction to update preferences", err.Error()) + } + } + } } else { - result.Data = preference + result.Err = s.saveOrUpdate(db, preferences[0]) } storeChannel <- result @@ -95,6 +139,16 @@ func (s SqlPreferenceStore) Update(preference *model.Preference) StoreChannel { return storeChannel } +func (s SqlPreferenceStore) saveOrUpdate(queryable Queryable, preference *model.Preference) *model.AppError { + if result := s.save(queryable, preference); result.Err != nil { + if result := s.update(queryable, preference); result.Err != nil { + return result.Err + } + } + + return nil +} + func (s SqlPreferenceStore) GetByName(userId string, category string, name string) StoreChannel { storeChannel := make(StoreChannel) -- cgit v1.2.3-1-g7c22