From 440790dad61563d6c0a2e9f3623b261026e42183 Mon Sep 17 00:00:00 2001 From: Kirill Krotov Date: Wed, 9 Feb 2022 17:26:16 +0300 Subject: [PATCH] [MM-39631] mirgate user store to sqlx (#19403) Co-authored-by: Mattermod --- api4/apitestlib.go | 5 +- app/helper_test.go | 4 +- app/slashcommands/helper_test.go | 3 +- model/user.go | 14 +- store/opentracinglayer/opentracinglayer.go | 18 ++ store/retrylayer/retrylayer.go | 21 ++ store/sqlstore/user_store.go | 289 ++++++++++++--------- store/store.go | 1 + store/storetest/mocks/UserStore.go | 14 + store/timerlayer/timerlayer.go | 16 ++ 10 files changed, 258 insertions(+), 127 deletions(-) diff --git a/api4/apitestlib.go b/api4/apitestlib.go index 512c308137..27b59fad74 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -417,7 +417,10 @@ func (th *TestHelper) InitLogin() *TestHelper { th.TeamAdminUser = userCache.TeamAdminUser.DeepCopy() th.BasicUser = userCache.BasicUser.DeepCopy() th.BasicUser2 = userCache.BasicUser2.DeepCopy() - mainHelper.GetSQLStore().GetMaster().Insert(th.SystemAdminUser, th.TeamAdminUser, th.BasicUser, th.BasicUser2, th.SystemManagerUser) + + users := []*model.User{th.SystemAdminUser, th.TeamAdminUser, th.BasicUser, th.BasicUser2, th.SystemManagerUser} + mainHelper.GetSQLStore().User().InsertUsers(users) + // restore non hashed password for login th.SystemAdminUser.Password = "Pa$$word11" th.TeamAdminUser.Password = "Pa$$word11" diff --git a/app/helper_test.go b/app/helper_test.go index 359c2780e5..ea2e002646 100644 --- a/app/helper_test.go +++ b/app/helper_test.go @@ -227,7 +227,9 @@ func (th *TestHelper) InitBasic() *TestHelper { th.SystemAdminUser = userCache.SystemAdminUser.DeepCopy() th.BasicUser = userCache.BasicUser.DeepCopy() th.BasicUser2 = userCache.BasicUser2.DeepCopy() - mainHelper.GetSQLStore().GetMaster().Insert(th.SystemAdminUser, th.BasicUser, th.BasicUser2) + + users := []*model.User{th.SystemAdminUser, th.BasicUser, th.BasicUser2} + mainHelper.GetSQLStore().User().InsertUsers(users) th.BasicTeam = th.CreateTeam() diff --git a/app/slashcommands/helper_test.go b/app/slashcommands/helper_test.go index 6cfeb9e0c6..66d1777d2c 100644 --- a/app/slashcommands/helper_test.go +++ b/app/slashcommands/helper_test.go @@ -177,7 +177,8 @@ func (th *TestHelper) initBasic() *TestHelper { th.SystemAdminUser = userCache.SystemAdminUser.DeepCopy() th.BasicUser = userCache.BasicUser.DeepCopy() th.BasicUser2 = userCache.BasicUser2.DeepCopy() - mainHelper.GetSQLStore().GetMaster().Insert(th.SystemAdminUser, th.BasicUser, th.BasicUser2) + users := []*model.User{th.SystemAdminUser, th.BasicUser, th.BasicUser2} + mainHelper.GetSQLStore().User().InsertUsers(users) th.BasicTeam = th.createTeam() diff --git a/model/user.go b/model/user.go index 5035f9a520..6688c3f57b 100644 --- a/model/user.go +++ b/model/user.go @@ -95,13 +95,13 @@ type User struct { MfaActive bool `json:"mfa_active,omitempty"` MfaSecret string `json:"mfa_secret,omitempty"` RemoteId *string `json:"remote_id,omitempty"` - LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"` - IsBot bool `db:"-" json:"is_bot,omitempty"` - BotDescription string `db:"-" json:"bot_description,omitempty"` - BotLastIconUpdate int64 `db:"-" json:"bot_last_icon_update,omitempty"` - TermsOfServiceId string `db:"-" json:"terms_of_service_id,omitempty"` - TermsOfServiceCreateAt int64 `db:"-" json:"terms_of_service_create_at,omitempty"` - DisableWelcomeEmail bool `db:"-" json:"disable_welcome_email"` + LastActivityAt int64 `json:"last_activity_at,omitempty"` + IsBot bool `json:"is_bot,omitempty"` + BotDescription string `json:"bot_description,omitempty"` + BotLastIconUpdate int64 `json:"bot_last_icon_update,omitempty"` + TermsOfServiceId string `json:"terms_of_service_id,omitempty"` + TermsOfServiceCreateAt int64 `json:"terms_of_service_create_at,omitempty"` + DisableWelcomeEmail bool `json:"disable_welcome_email"` } //msgp UserMap diff --git a/store/opentracinglayer/opentracinglayer.go b/store/opentracinglayer/opentracinglayer.go index ac4ee8aa7b..a069e779cc 100644 --- a/store/opentracinglayer/opentracinglayer.go +++ b/store/opentracinglayer/opentracinglayer.go @@ -10502,6 +10502,24 @@ func (s *OpenTracingLayerUserStore) InferSystemInstallDate() (int64, error) { return result, err } +func (s *OpenTracingLayerUserStore) InsertUsers(users []*model.User) error { + origCtx := s.Root.Store.Context() + span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.InsertUsers") + s.Root.Store.SetContext(newCtx) + defer func() { + s.Root.Store.SetContext(origCtx) + }() + + defer span.Finish() + err := s.UserStore.InsertUsers(users) + if err != nil { + span.LogFields(spanlog.Error(err)) + ext.Error.Set(span, true) + } + + return err +} + func (s *OpenTracingLayerUserStore) InvalidateProfileCacheForUser(userID string) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.InvalidateProfileCacheForUser") diff --git a/store/retrylayer/retrylayer.go b/store/retrylayer/retrylayer.go index 83b4297b7b..e71001e715 100644 --- a/store/retrylayer/retrylayer.go +++ b/store/retrylayer/retrylayer.go @@ -11977,6 +11977,27 @@ func (s *RetryLayerUserStore) InferSystemInstallDate() (int64, error) { } +func (s *RetryLayerUserStore) InsertUsers(users []*model.User) error { + + tries := 0 + for { + err := s.UserStore.InsertUsers(users) + if err == nil { + return nil + } + if !isRepeatableError(err) { + return err + } + tries++ + if tries >= 3 { + err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures") + return err + } + timepkg.Sleep(100 * timepkg.Millisecond) + } + +} + func (s *RetryLayerUserStore) InvalidateProfileCacheForUser(userID string) { s.UserStore.InvalidateProfileCacheForUser(userID) diff --git a/store/sqlstore/user_store.go b/store/sqlstore/user_store.go index e54256ecde..0baff74af6 100644 --- a/store/sqlstore/user_store.go +++ b/store/sqlstore/user_store.go @@ -12,7 +12,6 @@ import ( "strings" sq "github.com/Masterminds/squirrel" - "github.com/mattermost/gorp" "github.com/pkg/errors" "golang.org/x/sync/errgroup" @@ -81,6 +80,32 @@ func newSqlUserStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) s return us } +func (us SqlUserStore) insert(user *model.User) (sql.Result, error) { + query := `INSERT INTO Users + (Id, CreateAt, UpdateAt, DeleteAt, Username, Password, AuthData, AuthService, + Email, EmailVerified, Nickname, FirstName, LastName, Position, Roles, AllowMarketing, + Props, NotifyProps, LastPasswordUpdate, LastPictureUpdate, FailedAttempts, + Locale, Timezone, MfaActive, MfaSecret, RemoteId) + VALUES + (:Id, :CreateAt, :UpdateAt, :DeleteAt, :Username, :Password, :AuthData, :AuthService, + :Email, :EmailVerified, :Nickname, :FirstName, :LastName, :Position, :Roles, :AllowMarketing, + :Props, :NotifyProps, :LastPasswordUpdate, :LastPictureUpdate, :FailedAttempts, + :Locale, :Timezone, :MfaActive, :MfaSecret, :RemoteId)` + + return us.GetMasterX().NamedExec(query, user) +} + +func (us SqlUserStore) InsertUsers(users []*model.User) error { + for _, user := range users { + _, err := us.insert(user) + if err != nil { + return err + } + } + + return nil +} + func (us SqlUserStore) Save(user *model.User) (*model.User, error) { if user.Id != "" && !user.IsRemote() { return nil, store.NewErrInvalidInput("User", "id", user.Id) @@ -91,7 +116,7 @@ func (us SqlUserStore) Save(user *model.User) (*model.User, error) { return nil, err } - if err := us.GetMaster().Insert(user); err != nil { + if _, err := us.insert(user); err != nil { if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique"}) { return nil, store.NewErrInvalidInput("User", "email", user.Email) } @@ -117,7 +142,7 @@ func (us SqlUserStore) DeactivateGuests() ([]string, error) { return nil, errors.Wrap(err, "deactivate_guests_tosql") } - _, err = us.GetMaster().Exec(queryString, args...) + _, err = us.GetMasterX().Exec(queryString, args...) if err != nil { return nil, errors.Wrap(err, "failed to update Users with roles=system_guest") } @@ -130,7 +155,7 @@ func (us SqlUserStore) DeactivateGuests() ([]string, error) { } userIds := []string{} - _, err = us.GetMaster().Select(&userIds, queryString, args...) + err = us.GetMasterX().Select(&userIds, queryString, args...) if err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -145,16 +170,16 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) (*model. return nil, err } - oldUserResult, err := us.GetMaster().Get(model.User{}, user.Id) + oldUser := model.User{} + err := us.GetMasterX().Get(&oldUser, "SELECT * FROM Users WHERE Id=?", user.Id) if err != nil { return nil, errors.Wrapf(err, "failed to get User with userId=%s", user.Id) } - if oldUserResult == nil { + if oldUser.Id == "" { return nil, store.NewErrInvalidInput("User", "id", user.Id) } - oldUser := oldUserResult.(*model.User) user.CreateAt = oldUser.CreateAt user.AuthData = oldUser.AuthData user.AuthService = oldUser.AuthService @@ -187,7 +212,17 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) (*model. user.UpdateMentionKeysFromUsername(oldUser.Username) } - count, err := us.GetMaster().Update(user) + query := `UPDATE Users + SET CreateAt=:CreateAt, UpdateAt=:UpdateAt, DeleteAt=:DeleteAt, Username=:Username, Password=:Password, + AuthData=:AuthData, AuthService=:AuthService,Email=:Email, EmailVerified=:EmailVerified, + Nickname=:Nickname, FirstName=:FirstName, LastName=:LastName, Position=:Position, Roles=:Roles, + AllowMarketing=:AllowMarketing, Props=:Props, NotifyProps=:NotifyProps, + LastPasswordUpdate=:LastPasswordUpdate, LastPictureUpdate=:LastPictureUpdate, + FailedAttempts=:FailedAttempts,Locale=:Locale, Timezone=:Timezone, MfaActive=:MfaActive, + MfaSecret=:MfaSecret, RemoteId=:RemoteId + WHERE Id=:Id` + + res, err := us.GetMasterX().NamedExec(query, user) if err != nil { if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique"}) { return nil, store.NewErrConflict("Email", err, user.Email) @@ -198,21 +233,23 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) (*model. return nil, errors.Wrapf(err, "failed to update User with userId=%s", user.Id) } + count, err := res.RowsAffected() + if err != nil { + return nil, errors.Wrap(err, "failed to get rows_affected") + } if count > 1 { return nil, fmt.Errorf("multiple users were update: userId=%s, count=%d", user.Id, count) } user.Sanitize(map[string]bool{}) oldUser.Sanitize(map[string]bool{}) - return &model.UserUpdate{New: user, Old: oldUser}, nil + return &model.UserUpdate{New: user, Old: &oldUser}, nil } func (us SqlUserStore) UpdateNotifyProps(userID string, props map[string]string) error { - if _, err := us.GetMaster().Exec(`UPDATE Users - SET NotifyProps = :NotifyProps - WHERE Id = :UserId`, map[string]interface{}{ - "NotifyProps": model.MapToJSON(props), - "UserId": userID}); err != nil { + if _, err := us.GetMasterX().Exec(`UPDATE Users + SET NotifyProps = ? + WHERE Id = ?`, model.MapToJSON(props), userID); err != nil { return errors.Wrapf(err, "failed to update User with userId=%s", userID) } @@ -222,7 +259,7 @@ func (us SqlUserStore) UpdateNotifyProps(userID string, props map[string]string) func (us SqlUserStore) UpdateLastPictureUpdate(userId string) error { curTime := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET LastPictureUpdate = ?, UpdateAt = ? WHERE Id = ?", curTime, curTime, userId); err != nil { return errors.Wrapf(err, "failed to update User with userId=%s", userId) } @@ -232,7 +269,7 @@ func (us SqlUserStore) UpdateLastPictureUpdate(userId string) error { func (us SqlUserStore) ResetLastPictureUpdate(userId string) error { curTime := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :PictureUpdateTime, UpdateAt = :UpdateTime WHERE Id = :UserId", map[string]interface{}{"PictureUpdateTime": 0, "UpdateTime": curTime, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET LastPictureUpdate = ?, UpdateAt = ? WHERE Id = ?", 0, curTime, userId); err != nil { return errors.Wrapf(err, "failed to update User with userId=%s", userId) } @@ -242,7 +279,7 @@ func (us SqlUserStore) ResetLastPictureUpdate(userId string) error { func (us SqlUserStore) UpdateUpdateAt(userId string) (int64, error) { curTime := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET UpdateAt = ? WHERE Id = ?", curTime, userId); err != nil { return curTime, errors.Wrapf(err, "failed to update User with userId=%s", userId) } @@ -252,7 +289,7 @@ func (us SqlUserStore) UpdateUpdateAt(userId string) (int64, error) { func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) error { updateAt := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET Password = :Password, LastPasswordUpdate = :LastPasswordUpdate, UpdateAt = :UpdateAt, AuthData = NULL, AuthService = '', FailedAttempts = 0 WHERE Id = :UserId", map[string]interface{}{"Password": hashedPassword, "LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET Password = ?, LastPasswordUpdate = ?, UpdateAt = ?, AuthData = NULL, AuthService = '', FailedAttempts = 0 WHERE Id = ?", hashedPassword, updateAt, updateAt, userId); err != nil { return errors.Wrapf(err, "failed to update User with userId=%s", userId) } @@ -260,7 +297,7 @@ func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) error { } func (us SqlUserStore) UpdateFailedPasswordAttempts(userId string, attempts int) error { - if _, err := us.GetMaster().Exec("UPDATE Users SET FailedAttempts = :FailedAttempts WHERE Id = :UserId", map[string]interface{}{"FailedAttempts": attempts, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET FailedAttempts = ? WHERE Id = ?", attempts, userId); err != nil { return errors.Wrapf(err, "failed to update User with userId=%s", userId) } @@ -270,28 +307,30 @@ func (us SqlUserStore) UpdateFailedPasswordAttempts(userId string, attempts int) func (us SqlUserStore) UpdateAuthData(userId string, service string, authData *string, email string, resetMfa bool) (string, error) { updateAt := model.GetMillis() - query := ` - UPDATE - Users - SET - Password = '', - LastPasswordUpdate = :LastPasswordUpdate, - UpdateAt = :UpdateAt, - FailedAttempts = 0, - AuthService = :AuthService, - AuthData = :AuthData` + updateQuery := us.getQueryBuilder().Update("Users"). + Set("Password", ""). + Set("LastPasswordUpdate", updateAt). + Set("UpdateAt", updateAt). + Set("FailedAttempts", 0). + Set("AuthService", service). + Set("AuthData", authData). + Where(sq.Eq{"Id": userId}) if email != "" { - query += ", Email = lower(:Email)" + updateQuery = updateQuery.Set("Email", sq.Expr("lower(?)", email)) } if resetMfa { - query += ", MfaActive = false, MfaSecret = ''" + updateQuery = updateQuery.Set("MfaActive", false). + Set("MfaSecret", "") } - query += " WHERE Id = :UserId" + queryString, args, err := updateQuery.ToSql() + if err != nil { + return "", errors.Wrap(err, "update_auth_data_tosql") + } - if _, err := us.GetMaster().Exec(query, map[string]interface{}{"LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId, "AuthService": service, "AuthData": authData, "Email": email}); err != nil { + if _, err := us.GetMasterX().Exec(queryString, args...); err != nil { if IsUniqueConstraintError(err, []string{"Email", "users_email_key", "idx_users_email_unique", "AuthData", "users_authdata_key"}) { return "", store.NewErrInvalidInput("User", "id", userId) } @@ -323,8 +362,9 @@ func (us SqlUserStore) ResetAuthDataToEmailForUsers(service string, userIDs []st if err != nil { return 0, errors.Wrap(err, "select_count_users_tosql") } - numAffected, err := us.GetReplica().SelectInt(query, args...) - return int(numAffected), err + var numAffected int + err = us.GetReplicaX().Get(&numAffected, query, args...) + return numAffected, err } builder := us.getQueryBuilder(). Update("Users"). @@ -334,7 +374,7 @@ func (us SqlUserStore) ResetAuthDataToEmailForUsers(service string, userIDs []st if err != nil { return 0, errors.Wrap(err, "update_users_tosql") } - result, err := us.GetMaster().Exec(query, args...) + result, err := us.GetMasterX().Exec(query, args...) if err != nil { return 0, errors.Wrap(err, "failed to update users' AuthData") } @@ -345,7 +385,7 @@ func (us SqlUserStore) ResetAuthDataToEmailForUsers(service string, userIDs []st func (us SqlUserStore) UpdateMfaSecret(userId, secret string) error { updateAt := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET MfaSecret = :Secret, UpdateAt = :UpdateAt WHERE Id = :UserId", map[string]interface{}{"Secret": secret, "UpdateAt": updateAt, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET MfaSecret = ?, UpdateAt = ? WHERE Id = ?", secret, updateAt, userId); err != nil { return errors.Wrapf(err, "failed to update User with userId=%s", userId) } @@ -355,7 +395,7 @@ func (us SqlUserStore) UpdateMfaSecret(userId, secret string) error { func (us SqlUserStore) UpdateMfaActive(userId string, active bool) error { updateAt := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET MfaActive = :Active, UpdateAt = :UpdateAt WHERE Id = :UserId", map[string]interface{}{"Active": active, "UpdateAt": updateAt, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET MfaActive = ?, UpdateAt = ? WHERE Id = ?", active, updateAt, userId); err != nil { return errors.Wrapf(err, "failed to update User with userId=%s", userId) } @@ -370,7 +410,7 @@ func (us SqlUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User return nil, errors.Wrap(err, "users_get_many_tosql") } - var users []*model.User + users := []*model.User{} if _, err := us.SqlStore.DBFromContext(ctx).Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "users_get_many_select") } @@ -422,8 +462,8 @@ func (us SqlUserStore) GetAll() ([]*model.User, error) { return nil, errors.Wrap(err, "get_all_users_tosql") } - var data []*model.User - if _, err := us.GetReplica().Select(&data, queryString, args...); err != nil { + data := []*model.User{} + if err := us.GetReplicaX().Select(&data, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } return data, nil @@ -440,8 +480,8 @@ func (us SqlUserStore) GetAllAfter(limit int, afterId string) ([]*model.User, er return nil, errors.Wrap(err, "get_all_after_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -449,7 +489,8 @@ func (us SqlUserStore) GetAllAfter(limit int, afterId string) ([]*model.User, er } func (us SqlUserStore) GetEtagForAllProfiles() string { - updateAt, err := us.GetReplica().SelectInt("SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1") + var updateAt int64 + err := us.GetReplicaX().Get(&updateAt, "SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1") if err != nil { return fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) } @@ -478,8 +519,8 @@ func (us SqlUserStore) GetAllProfiles(options *model.UserGetOptions) ([]*model.U return nil, errors.Wrap(err, "get_all_profiles_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to get User profiles") } @@ -624,7 +665,8 @@ func applyTeamGroupConstrainedFilter(query sq.SelectBuilder, teamId string) sq.S } func (us SqlUserStore) GetEtagForProfiles(teamId string) string { - updateAt, err := us.GetReplica().SelectInt("SELECT UpdateAt FROM Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId}) + var updateAt int64 + err := us.GetReplicaX().Get(&updateAt, "SELECT UpdateAt FROM Users, TeamMembers WHERE TeamMembers.TeamId = ? AND Users.Id = TeamMembers.UserId ORDER BY UpdateAt DESC LIMIT 1", teamId) if err != nil { return fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) } @@ -655,8 +697,8 @@ func (us SqlUserStore) GetProfiles(options *model.UserGetOptions) ([]*model.User return nil, errors.Wrap(err, "get_etag_for_profiles_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -689,8 +731,8 @@ func (us SqlUserStore) GetProfilesInChannel(options *model.UserGetOptions) ([]*m return nil, errors.Wrap(err, "get_profiles_in_channel_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -728,8 +770,8 @@ func (us SqlUserStore) GetProfilesInChannelByStatus(options *model.UserGetOption return nil, errors.Wrap(err, "get_profiles_in_channel_by_status_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -752,7 +794,7 @@ func (us SqlUserStore) GetAllProfilesInChannel(ctx context.Context, channelID st return nil, errors.Wrap(err, "get_all_profiles_in_channel_tosql") } - var users []*model.User + users := []*model.User{} rows, err := us.SqlStore.DBFromContext(ctx).Db.Query(queryString, args...) if err != nil { return nil, errors.Wrap(err, "failed to find Users") @@ -810,8 +852,8 @@ func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, return nil, errors.Wrap(err, "get_profiles_not_in_channel_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -852,8 +894,8 @@ func (us SqlUserStore) GetProfilesWithoutTeam(options *model.UserGetOptions) ([] return nil, errors.Wrap(err, "get_profiles_without_team_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -880,8 +922,8 @@ func (us SqlUserStore) GetProfilesByUsernames(usernames []string, viewRestrictio return nil, errors.Wrap(err, "get_profiles_by_usernames") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -909,8 +951,8 @@ func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limi return nil, errors.Wrap(err, "get_recently_active_users_for_team_tosql") } - var users []*UserWithLastActivityAt - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*UserWithLastActivityAt{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -940,8 +982,8 @@ func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int, view return nil, errors.Wrap(err, "get_new_users_for_team_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -1022,7 +1064,7 @@ func (us SqlUserStore) GetProfileByGroupChannelIdsForUser(userId string, channel } usersWithChannel := []*UserWithChannel{} - if _, err := us.GetReplica().Select(&usersWithChannel, queryString, args...); err != nil { + if err := us.GetReplicaX().Select(&usersWithChannel, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -1048,8 +1090,8 @@ func (us SqlUserStore) GetSystemAdminProfiles() (map[string]*model.User, error) return nil, errors.Wrap(err, "get_system_admin_profiles_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -1072,7 +1114,7 @@ func (us SqlUserStore) GetByEmail(email string) (*model.User, error) { } user := model.User{} - if err := us.GetReplica().SelectOne(&user, queryString, args...); err != nil { + if err := us.GetReplicaX().Get(&user, queryString, args...); err != nil { if err == sql.ErrNoRows { return nil, errors.Wrap(store.NewErrNotFound("User", fmt.Sprintf("email=%s", email)), "failed to find User") } @@ -1098,7 +1140,7 @@ func (us SqlUserStore) GetByAuth(authData *string, authService string) (*model.U } user := model.User{} - if err := us.GetReplica().SelectOne(&user, queryString, args...); err == sql.ErrNoRows { + if err := us.GetReplicaX().Get(&user, queryString, args...); err == sql.ErrNoRows { return nil, store.NewErrNotFound("User", fmt.Sprintf("authData=%s, authService=%s", *authData, authService)) } else if err != nil { return nil, errors.Wrapf(err, "failed to find User with authData=%s and authService=%s", *authData, authService) @@ -1116,8 +1158,8 @@ func (us SqlUserStore) GetAllUsingAuthService(authService string) ([]*model.User return nil, errors.Wrap(err, "get_all_using_auth_service_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrapf(err, "failed to find Users with authService=%s", authService) } @@ -1134,8 +1176,8 @@ func (us SqlUserStore) GetAllNotInAuthService(authServices []string) ([]*model.U return nil, errors.Wrap(err, "get_all_not_in_auth_service_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrapf(err, "failed to find Users with authServices in %v", authServices) } @@ -1150,8 +1192,8 @@ func (us SqlUserStore) GetByUsername(username string) (*model.User, error) { return nil, errors.Wrap(err, "get_by_username_tosql") } - var user *model.User - if err := us.GetReplica().SelectOne(&user, queryString, args...); err != nil { + user := model.User{} + if err := us.GetReplicaX().Get(&user, queryString, args...); err != nil { if err == sql.ErrNoRows { return nil, errors.Wrap(store.NewErrNotFound("User", fmt.Sprintf("username=%s", username)), "failed to find User") } @@ -1159,7 +1201,7 @@ func (us SqlUserStore) GetByUsername(username string) (*model.User, error) { return nil, errors.Wrapf(err, "failed to find User with username=%s", username) } - return user, nil + return &user, nil } func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail bool) (*model.User, error) { @@ -1180,7 +1222,7 @@ func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allo } users := []*model.User{} - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -1198,7 +1240,7 @@ func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allo func (us SqlUserStore) VerifyEmail(userId, email string) (string, error) { curTime := model.GetMillis() - if _, err := us.GetMaster().Exec("UPDATE Users SET Email = lower(:email), EmailVerified = true, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"email": email, "Time": curTime, "UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("UPDATE Users SET Email = lower(?), EmailVerified = true, UpdateAt = ? WHERE Id = ?", email, curTime, userId); err != nil { return "", errors.Wrapf(err, "failed to update Users with userId=%s and email=%s", userId, email) } @@ -1206,7 +1248,7 @@ func (us SqlUserStore) VerifyEmail(userId, email string) (string, error) { } func (us SqlUserStore) PermanentDelete(userId string) error { - if _, err := us.GetMaster().Exec("DELETE FROM Users WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil { + if _, err := us.GetMasterX().Exec("DELETE FROM Users WHERE Id = ?", userId); err != nil { return errors.Wrapf(err, "failed to delete User with userId=%s", userId) } return nil @@ -1249,7 +1291,8 @@ func (us SqlUserStore) Count(options model.UserCountOptions) (int64, error) { return int64(0), errors.Wrap(err, "count_tosql") } - count, err := us.GetReplica().SelectInt(queryString, args...) + var count int64 + err = us.GetReplicaX().Get(&count, queryString, args...) if err != nil { return int64(0), errors.Wrap(err, "failed to count Users") } @@ -1259,7 +1302,7 @@ func (us SqlUserStore) Count(options model.UserCountOptions) (int64, error) { func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64, options model.UserCountOptions) (int64, error) { time := model.GetMillis() - timePeriod - query := us.getQueryBuilder().Select("COUNT(*)").From("Status AS s").Where("LastActivityAt > :Time", map[string]interface{}{"Time": time}) + query := us.getQueryBuilder().Select("COUNT(*)").From("Status AS s").Where("LastActivityAt > ?", time) if !options.IncludeBotAccounts { query = query.LeftJoin("Bots ON s.UserId = Bots.UserId").Where("Bots.UserId IS NULL") @@ -1275,7 +1318,8 @@ func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64, options model.User return 0, errors.Wrap(err, "analytics_active_count_tosql") } - v, err := us.GetReplica().SelectInt(queryStr, args...) + var v int64 + err = us.GetReplicaX().Get(&v, queryStr, args...) if err != nil { return 0, errors.Wrap(err, "failed to count Users") } @@ -1283,7 +1327,7 @@ func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64, options model.User } func (us SqlUserStore) AnalyticsActiveCountForPeriod(startTime int64, endTime int64, options model.UserCountOptions) (int64, error) { - query := us.getQueryBuilder().Select("COUNT(*)").From("Status AS s").Where("LastActivityAt > :StartTime AND LastActivityAt <= :EndTime", map[string]interface{}{"StartTime": startTime, "EndTime": endTime}) + query := us.getQueryBuilder().Select("COUNT(*)").From("Status AS s").Where("LastActivityAt > ? AND LastActivityAt <= ?", startTime, endTime) if !options.IncludeBotAccounts { query = query.LeftJoin("Bots ON s.UserId = Bots.UserId").Where("Bots.UserId IS NULL") @@ -1299,7 +1343,8 @@ func (us SqlUserStore) AnalyticsActiveCountForPeriod(startTime int64, endTime in return 0, errors.Wrap(err, "Failed to build query.") } - v, err := us.GetReplica().SelectInt(queryStr, args...) + var v int64 + err = us.GetReplicaX().Get(&v, queryStr, args...) if err != nil { return 0, errors.Wrap(err, "Unable to get the active users during the requested period.") } @@ -1312,10 +1357,12 @@ func (us SqlUserStore) GetUnreadCount(userId string) (int64, error) { FROM Channels c INNER JOIN ChannelMembers cm ON cm.ChannelId = c.Id - AND cm.UserId = :UserId + AND cm.UserId = ? AND c.DeleteAt = 0 ` - count, err := us.GetReplica().SelectInt(query, map[string]interface{}{"UserId": userId}) + + var count int64 + err := us.GetReplicaX().Get(&count, query, userId) if err != nil { return count, errors.Wrapf(err, "failed to count unread Channels for userId=%s", userId) } @@ -1324,7 +1371,8 @@ func (us SqlUserStore) GetUnreadCount(userId string) (int64, error) { } func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string) (int64, error) { - count, err := us.GetReplica().SelectInt("SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = cm.ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}) + var count int64 + err := us.GetReplicaX().Get(&count, "SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = cm.ChannelId AND cm.ChannelId = ? AND cm.UserId = ?", channelId, userId) if err != nil { return 0, errors.Wrapf(err, "failed to get unread count for channelId=%s and userId=%s", channelId, userId) } @@ -1332,7 +1380,8 @@ func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string) } func (us SqlUserStore) GetAnyUnreadPostCountForChannel(userId string, channelId string) (int64, error) { - count, err := us.GetReplica().SelectInt("SELECT SUM(c.TotalMsgCount - cm.MsgCount) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = cm.ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}) + var count int64 + err := us.GetReplicaX().Get(&count, "SELECT SUM(c.TotalMsgCount - cm.MsgCount) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = cm.ChannelId AND cm.ChannelId = ? AND cm.UserId = ?", channelId, userId) if err != nil { return count, errors.Wrapf(err, "failed to get any unread count for channelId=%s and userId=%s", channelId, userId) } @@ -1488,8 +1537,8 @@ func (us SqlUserStore) performSearch(query sq.SelectBuilder, term string, option return nil, errors.Wrap(err, "perform_search_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrapf(err, "failed to find Users with term=%s and searchType=%v", term, searchType) } for _, u := range users { @@ -1500,7 +1549,8 @@ func (us SqlUserStore) performSearch(query sq.SelectBuilder, term string, option } func (us SqlUserStore) AnalyticsGetInactiveUsersCount() (int64, error) { - count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0") + var count int64 + err := us.GetReplicaX().Get(&count, "SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0") if err != nil { return int64(0), errors.Wrap(err, "failed to count inactive Users") } @@ -1508,7 +1558,8 @@ func (us SqlUserStore) AnalyticsGetInactiveUsersCount() (int64, error) { } func (us SqlUserStore) AnalyticsGetExternalUsers(hostDomain string) (bool, error) { - count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE LOWER(Email) NOT LIKE :HostDomain", map[string]interface{}{"HostDomain": "%@" + strings.ToLower(hostDomain)}) + var count int64 + err := us.GetReplicaX().Get(&count, "SELECT COUNT(Id) FROM Users WHERE LOWER(Email) NOT LIKE ?", "%@"+strings.ToLower(hostDomain)) if err != nil { return false, errors.Wrap(err, "failed to count inactive Users") } @@ -1516,7 +1567,8 @@ func (us SqlUserStore) AnalyticsGetExternalUsers(hostDomain string) (bool, error } func (us SqlUserStore) AnalyticsGetGuestCount() (int64, error) { - count, err := us.GetReplica().SelectInt("SELECT count(*) FROM Users WHERE Roles LIKE :Roles and DeleteAt = 0", map[string]interface{}{"Roles": "%system_guest%"}) + var count int64 + err := us.GetReplicaX().Get(&count, "SELECT count(*) FROM Users WHERE Roles LIKE ? and DeleteAt = 0", "%system_guest%") if err != nil { return int64(0), errors.Wrap(err, "failed to count guest Users") } @@ -1524,7 +1576,8 @@ func (us SqlUserStore) AnalyticsGetGuestCount() (int64, error) { } func (us SqlUserStore) AnalyticsGetSystemAdminCount() (int64, error) { - count, err := us.GetReplica().SelectInt("SELECT count(*) FROM Users WHERE Roles LIKE :Roles and DeleteAt = 0", map[string]interface{}{"Roles": "%system_admin%"}) + var count int64 + err := us.GetReplicaX().Get(&count, "SELECT count(*) FROM Users WHERE Roles LIKE ? and DeleteAt = 0", "%system_admin%") if err != nil { return int64(0), errors.Wrap(err, "failed to count system admin Users") } @@ -1532,7 +1585,7 @@ func (us SqlUserStore) AnalyticsGetSystemAdminCount() (int64, error) { } func (us SqlUserStore) GetProfilesNotInTeam(teamId string, groupConstrained bool, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, error) { - var users []*model.User + users := []*model.User{} query := us.usersQuery. LeftJoin("TeamMembers tm ON ( tm.UserId = u.Id AND tm.DeleteAt = 0 AND tm.TeamId = ? )", teamId). Where("tm.UserId IS NULL"). @@ -1550,7 +1603,7 @@ func (us SqlUserStore) GetProfilesNotInTeam(teamId string, groupConstrained bool return nil, errors.Wrap(err, "get_profiles_not_in_team_tosql") } - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -1568,12 +1621,13 @@ func (us SqlUserStore) GetEtagForProfilesNotInTeam(teamId string) string { Users as u LEFT JOIN TeamMembers tm ON tm.UserId = u.Id - AND tm.TeamId = :TeamId + AND tm.TeamId = ? AND tm.DeleteAt = 0 WHERE tm.UserId IS NULL ` - etag, err := us.GetReplica().SelectStr(querystr, map[string]interface{}{"TeamId": teamId}) + var etag string + err := us.GetReplicaX().Get(&etag, querystr, teamId) if err != nil { return fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) } @@ -1586,16 +1640,16 @@ func (us SqlUserStore) ClearAllCustomRoleAssignments() error { lastUserId := strings.Repeat("0", 26) for { - var transaction *gorp.Transaction + var transaction *sqlxTxWrapper var err error - if transaction, err = us.GetMaster().Begin(); err != nil { + if transaction, err = us.GetMasterX().Beginx(); err != nil { return errors.Wrap(err, "begin_transaction") } - defer finalizeTransaction(transaction) + defer finalizeTransactionX(transaction) - var users []*model.User - if _, err := transaction.Select(&users, "SELECT * from Users WHERE Id > :Id ORDER BY Id LIMIT 1000", map[string]interface{}{"Id": lastUserId}); err != nil { + users := []*model.User{} + if err := transaction.Select(&users, "SELECT * from Users WHERE Id > ? ORDER BY Id LIMIT 1000", lastUserId); err != nil { return errors.Wrapf(err, "failed to find Users with id > %s", lastUserId) } @@ -1619,7 +1673,7 @@ func (us SqlUserStore) ClearAllCustomRoleAssignments() error { newRolesString := strings.Join(newRoles, " ") if newRolesString != user.Roles { - if _, err := transaction.Exec("UPDATE Users SET Roles = :Roles WHERE Id = :Id", map[string]interface{}{"Roles": newRolesString, "Id": user.Id}); err != nil { + if _, err := transaction.Exec("UPDATE Users SET Roles = ? WHERE Id = ?", newRolesString, user.Id); err != nil { return errors.Wrap(err, "failed to update Users") } } @@ -1634,7 +1688,8 @@ func (us SqlUserStore) ClearAllCustomRoleAssignments() error { } func (us SqlUserStore) InferSystemInstallDate() (int64, error) { - createAt, err := us.GetReplica().SelectInt("SELECT CreateAt FROM Users WHERE CreateAt IS NOT NULL ORDER BY CreateAt ASC LIMIT 1") + var createAt int64 + err := us.GetReplicaX().Get(&createAt, "SELECT CreateAt FROM Users WHERE CreateAt IS NOT NULL ORDER BY CreateAt ASC LIMIT 1") if err != nil { return 0, errors.Wrap(err, "failed to infer system install date") } @@ -1643,7 +1698,7 @@ func (us SqlUserStore) InferSystemInstallDate() (int64, error) { } func (us SqlUserStore) GetUsersBatchForIndexing(startTime, endTime int64, limit int) ([]*model.UserForIndexing, error) { - var users []*model.User + users := []*model.User{} usersQuery, args, _ := us.usersQuery. Where(sq.GtOrEq{"u.CreateAt": startTime}). Where(sq.Lt{"u.CreateAt": endTime}). @@ -1742,8 +1797,8 @@ func (us SqlUserStore) GetTeamGroupUsers(teamID string) ([]*model.User, error) { return nil, errors.Wrap(err, "get_team_group_users_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -1762,8 +1817,8 @@ func (us SqlUserStore) GetChannelGroupUsers(channelID string) ([]*model.User, er return nil, errors.Wrap(err, "get_channel_group_users_tosql") } - var users []*model.User - if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil { + users := []*model.User{} + if err := us.GetReplicaX().Select(&users, queryString, args...); err != nil { return nil, errors.Wrap(err, "failed to find Users") } @@ -1808,11 +1863,11 @@ func applyViewRestrictionsFilter(query sq.SelectBuilder, restrictions *model.Vie } func (us SqlUserStore) PromoteGuestToUser(userId string) error { - transaction, err := us.GetMaster().Begin() + transaction, err := us.GetMasterX().Beginx() if err != nil { return errors.Wrap(err, "begin_transaction") } - defer finalizeTransaction(transaction) + defer finalizeTransactionX(transaction) user, err := us.Get(context.Background(), userId) if err != nil { @@ -1877,11 +1932,11 @@ func (us SqlUserStore) PromoteGuestToUser(userId string) error { } func (us SqlUserStore) DemoteUserToGuest(userID string) (*model.User, error) { - transaction, err := us.GetMaster().Begin() + transaction, err := us.GetMasterX().Beginx() if err != nil { return nil, errors.Wrap(err, "begin_transaction") } - defer finalizeTransaction(transaction) + defer finalizeTransactionX(transaction) user, err := us.Get(context.Background(), userID) if err != nil { @@ -1980,7 +2035,7 @@ func (us SqlUserStore) AutocompleteUsersInChannel(teamId, channelId, term string // relationship with a user. That means any user sharing any channel, including // direct and group channels. func (us SqlUserStore) GetKnownUsers(userId string) ([]string, error) { - var userIds []string + userIds := []string{} usersQuery, args, _ := us.getQueryBuilder(). Select("DISTINCT ocm.UserId"). From("ChannelMembers AS cm"). @@ -1988,7 +2043,7 @@ func (us SqlUserStore) GetKnownUsers(userId string) ([]string, error) { Where(sq.NotEq{"ocm.UserId": userId}). Where(sq.Eq{"cm.UserId": userId}). ToSql() - _, err := us.GetSearchReplica().Select(&userIds, usersQuery, args...) + err := us.GetSearchReplicaX().Select(&userIds, usersQuery, args...) if err != nil { return nil, errors.Wrap(err, "failed to find ChannelMembers") } @@ -2016,7 +2071,7 @@ func (us SqlUserStore) IsEmpty(excludeBots bool) (bool, error) { return false, errors.Wrapf(err, "users_is_empty_to_sql") } - if err = us.GetReplica().SelectOne(&hasRows, query, args...); err != nil { + if err = us.GetReplicaX().Get(&hasRows, query, args...); err != nil { return false, errors.Wrap(err, "failed to check if table is empty") } return !hasRows, nil diff --git a/store/store.go b/store/store.go index 4020f3c3b1..fc86edd452 100644 --- a/store/store.go +++ b/store/store.go @@ -437,6 +437,7 @@ type UserStore interface { AutocompleteUsersInChannel(teamID, channelID, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, error) GetKnownUsers(userID string) ([]string, error) IsEmpty(excludeBots bool) (bool, error) + InsertUsers(users []*model.User) error } type BotStore interface { diff --git a/store/storetest/mocks/UserStore.go b/store/storetest/mocks/UserStore.go index 06e0db7d94..4d9bc5b1f6 100644 --- a/store/storetest/mocks/UserStore.go +++ b/store/storetest/mocks/UserStore.go @@ -1023,6 +1023,20 @@ func (_m *UserStore) InferSystemInstallDate() (int64, error) { return r0, r1 } +// InsertUsers provides a mock function with given fields: users +func (_m *UserStore) InsertUsers(users []*model.User) error { + ret := _m.Called(users) + + var r0 error + if rf, ok := ret.Get(0).(func([]*model.User) error); ok { + r0 = rf(users) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // InvalidateProfileCacheForUser provides a mock function with given fields: userID func (_m *UserStore) InvalidateProfileCacheForUser(userID string) { _m.Called(userID) diff --git a/store/timerlayer/timerlayer.go b/store/timerlayer/timerlayer.go index 7848ad579a..a05f323f68 100644 --- a/store/timerlayer/timerlayer.go +++ b/store/timerlayer/timerlayer.go @@ -9461,6 +9461,22 @@ func (s *TimerLayerUserStore) InferSystemInstallDate() (int64, error) { return result, err } +func (s *TimerLayerUserStore) InsertUsers(users []*model.User) error { + start := timemodule.Now() + + err := s.UserStore.InsertUsers(users) + + elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second) + if s.Root.Metrics != nil { + success := "false" + if err == nil { + success = "true" + } + s.Root.Metrics.ObserveStoreMethodDuration("UserStore.InsertUsers", success, elapsed) + } + return err +} + func (s *TimerLayerUserStore) InvalidateProfileCacheForUser(userID string) { start := timemodule.Now()