diff --git a/store/sqlstore/bot_store.go b/store/sqlstore/bot_store.go index 169a8ad9a1..008d5ef76e 100644 --- a/store/sqlstore/bot_store.go +++ b/store/sqlstore/bot_store.go @@ -89,37 +89,33 @@ func (us SqlBotStore) Get(botUserId string, includeDeleted bool) (*model.Bot, er JOIN Users u ON (u.Id = b.UserId) WHERE - b.UserId = :user_id + b.UserId = ? ` + excludeDeletedSql + ` ` - var bot *model.Bot - if err := us.GetReplica().SelectOne(&bot, query, map[string]interface{}{"user_id": botUserId}); err == sql.ErrNoRows { + var bot model.Bot + if err := us.GetReplicaX().Get(&bot, query, botUserId); err == sql.ErrNoRows { return nil, store.NewErrNotFound("Bot", botUserId) } else if err != nil { return nil, errors.Wrapf(err, "selectone: user_id=%s", botUserId) } - return bot, nil + return &bot, nil } // GetAll fetches from all bots in the database. func (us SqlBotStore) GetAll(options *model.BotGetOptions) ([]*model.Bot, error) { - params := map[string]interface{}{ - "offset": options.Page * options.PerPage, - "limit": options.PerPage, - } - var conditions []string var conditionsSql string var additionalJoin string + var args []interface{} if !options.IncludeDeleted { conditions = append(conditions, "b.DeleteAt = 0") } if options.OwnerId != "" { - conditions = append(conditions, "b.OwnerId = :creator_id") - params["creator_id"] = options.OwnerId + conditions = append(conditions, "b.OwnerId = ?") + args = append(args, options.OwnerId) } if options.OnlyOrphaned { additionalJoin = "JOIN Users o ON (o.Id = b.OwnerId)" @@ -151,13 +147,15 @@ func (us SqlBotStore) GetAll(options *model.BotGetOptions) ([]*model.Bot, error) b.CreateAt ASC, u.Username ASC LIMIT - :limit + ? OFFSET - :offset + ? ` + // append limit, offset + args = append(args, options.PerPage, options.Page*options.PerPage) - var bots []*model.Bot - if _, err := us.GetReplica().Select(&bots, sql, params); err != nil { + bots := []*model.Bot{} + if err := us.GetReplicaX().Select(&bots, sql, args...); err != nil { return nil, errors.Wrap(err, "select") } @@ -174,7 +172,10 @@ func (us SqlBotStore) Save(bot *model.Bot) (*model.Bot, error) { return nil, err } - if err := us.GetMaster().Insert(botFromModel(bot)); err != nil { + if _, err := us.GetMasterX().NamedExec(`INSERT INTO Bots + (UserId, Description, OwnerId, LastIconUpdate, CreateAt, UpdateAt, DeleteAt) + VALUES + (:UserId, :Description, :OwnerId, :LastIconUpdate, :CreateAt, :UpdateAt, :DeleteAt)`, botFromModel(bot)); err != nil { return nil, errors.Wrapf(err, "insert: user_id=%s", bot.UserId) } @@ -203,9 +204,18 @@ func (us SqlBotStore) Update(bot *model.Bot) (*model.Bot, error) { oldBot.DeleteAt = bot.DeleteAt bot = oldBot - if count, err := us.GetMaster().Update(botFromModel(bot)); err != nil { + res, err := us.GetMasterX().NamedExec(`UPDATE Bots + SET Description=:Description, OwnerId=:OwnerId, LastIconUpdate=:LastIconUpdate, + UpdateAt=:UpdateAt, DeleteAt=:DeleteAt + WHERE UserId=:UserId`, botFromModel(bot)) + if err != nil { return nil, errors.Wrapf(err, "update: user_id=%s", bot.UserId) - } else if count > 1 { + } + count, err := res.RowsAffected() + if err != nil { + return nil, errors.Wrap(err, "error while getting rows_affected") + } + if count > 1 { return nil, fmt.Errorf("unexpected count while updating bot: count=%d, userId=%s", count, bot.UserId) } @@ -215,8 +225,8 @@ func (us SqlBotStore) Update(bot *model.Bot) (*model.Bot, error) { // PermanentDelete removes the bot from the database altogether. // If the corresponding user is to be deleted, it must be done via the user store. func (us SqlBotStore) PermanentDelete(botUserId string) error { - query := "DELETE FROM Bots WHERE UserId = :user_id" - if _, err := us.GetMaster().Exec(query, map[string]interface{}{"user_id": botUserId}); err != nil { + query := "DELETE FROM Bots WHERE UserId = ?" + if _, err := us.GetMasterX().Exec(query, botUserId); err != nil { return store.NewErrInvalidInput("Bot", "UserId", botUserId) } return nil diff --git a/store/sqlstore/sqlx_wrapper.go b/store/sqlstore/sqlx_wrapper.go index b91110b19e..66e5f2566a 100644 --- a/store/sqlstore/sqlx_wrapper.go +++ b/store/sqlstore/sqlx_wrapper.go @@ -78,6 +78,21 @@ func (w *sqlxDBWrapper) NamedExec(query string, arg interface{}) (sql.Result, er return w.DB.NamedExecContext(ctx, query, arg) } +func (w *sqlxDBWrapper) Exec(query string, args ...interface{}) (sql.Result, error) { + query = w.DB.Rebind(query) + + ctx, cancel := context.WithTimeout(context.Background(), w.queryTimeout) + defer cancel() + + if w.trace { + defer func(then time.Time) { + printArgs(query, time.Since(then), args) + }(time.Now()) + } + + return w.DB.ExecContext(ctx, query, args...) +} + func (w *sqlxDBWrapper) NamedQuery(query string, arg interface{}) (*sqlx.Rows, error) { if w.DB.DriverName() == model.DatabaseDriverPostgres { query = namedParamRegex.ReplaceAllStringFunc(query, strings.ToLower) @@ -164,6 +179,21 @@ func (w *sqlxTxWrapper) Get(dest interface{}, query string, args ...interface{}) return w.Tx.GetContext(ctx, dest, query, args...) } +func (w *sqlxTxWrapper) Exec(query string, args ...interface{}) (sql.Result, error) { + query = w.Tx.Rebind(query) + + ctx, cancel := context.WithTimeout(context.Background(), w.queryTimeout) + defer cancel() + + if w.trace { + defer func(then time.Time) { + printArgs(query, time.Since(then), args) + }(time.Now()) + } + + return w.Tx.ExecContext(ctx, query, args...) +} + func (w *sqlxTxWrapper) NamedExec(query string, arg interface{}) (sql.Result, error) { if w.Tx.DriverName() == model.DatabaseDriverPostgres { query = namedParamRegex.ReplaceAllStringFunc(query, strings.ToLower)