diff --git a/model/job.go b/model/job.go index 13c6154f55..e892b051b4 100644 --- a/model/job.go +++ b/model/job.go @@ -58,15 +58,15 @@ var AllJobTypes = [...]string{ } type Job struct { - Id string `json:"id"` - Type string `json:"type"` - Priority int64 `json:"priority"` - CreateAt int64 `json:"create_at"` - StartAt int64 `json:"start_at"` - LastActivityAt int64 `json:"last_activity_at"` - Status string `json:"status"` - Progress int64 `json:"progress"` - Data map[string]string `json:"data"` + Id string `json:"id"` + Type string `json:"type"` + Priority int64 `json:"priority"` + CreateAt int64 `json:"create_at"` + StartAt int64 `json:"start_at"` + LastActivityAt int64 `json:"last_activity_at"` + Status string `json:"status"` + Progress int64 `json:"progress"` + Data StringMap `json:"data"` } func (j *Job) IsValid() *AppError { diff --git a/model/utils.go b/model/utils.go index c57716f7c3..4e0fe38c90 100644 --- a/model/utils.go +++ b/model/utils.go @@ -98,6 +98,25 @@ func (sa *StringArray) Scan(value interface{}) error { return errors.New("received value is neither a byte slice nor string") } +// Scan converts database column value to StringMap +func (m *StringMap) Scan(value interface{}) error { + if value == nil { + return nil + } + + buf, ok := value.([]byte) + if ok { + return json.Unmarshal(buf, m) + } + + str, ok := value.(string) + if ok { + return json.Unmarshal([]byte(str), m) + } + + return errors.New("received value is neither a byte slice nor string") +} + var translateFunc i18n.TranslateFunc var translateFuncOnce sync.Once diff --git a/store/sqlstore/job_store.go b/store/sqlstore/job_store.go index 85bfd91fb1..69b42d0afc 100644 --- a/store/sqlstore/job_store.go +++ b/store/sqlstore/job_store.go @@ -11,7 +11,6 @@ import ( "time" sq "github.com/Masterminds/squirrel" - "github.com/mattermost/gorp" "github.com/pkg/errors" "github.com/mattermost/mattermost-server/v6/model" @@ -46,9 +45,24 @@ func (jss SqlJobStore) createIndexesIfNotExists() { } func (jss SqlJobStore) Save(job *model.Job) (*model.Job, error) { - if err := jss.GetMaster().Insert(job); err != nil { - return nil, errors.Wrap(err, "failed to save Job") + jsonData, err := json.Marshal(job.Data) + if err != nil { + return nil, errors.Wrap(err, "failed marshalling job data") } + query := jss.getQueryBuilder(). + Insert("Jobs"). + Columns("Id", "Type", "Priority", "CreateAt", "StartAt", "LastActivityAt", "Status", "Progress", "Data"). + Values(job.Id, job.Type, job.Priority, job.CreateAt, job.StartAt, job.LastActivityAt, job.Status, job.Progress, string(jsonData)) + + queryString, args, err := query.ToSql() + if err != nil { + return nil, errors.Wrap(err, "failed to generate sqlquery") + } + + if _, err = jss.GetMasterX().Exec(queryString, args...); err != nil { + return nil, errors.Wrap(err, "failed to save Preference") + } + return job, nil } @@ -67,7 +81,7 @@ func (jss SqlJobStore) UpdateOptimistically(job *model.Job, currentStatus string if err != nil { return false, errors.Wrap(err, "job_tosql") } - sqlResult, err := jss.GetMaster().Exec(query, args...) + sqlResult, err := jss.GetMasterX().Exec(query, args...) if err != nil { return false, errors.Wrap(err, "failed to update Job") } @@ -92,9 +106,9 @@ func (jss SqlJobStore) UpdateStatus(id string, status string) (*model.Job, error LastActivityAt: model.GetMillis(), } - if _, err := jss.GetMaster().UpdateColumns(func(col *gorp.ColumnMap) bool { - return col.ColumnName == "Status" || col.ColumnName == "LastActivityAt" - }, job); err != nil { + if _, err := jss.GetMasterX().NamedExec(`UPDATE Jobs + SET Status=:Status, LastActivityAt=:LastActivityAt + WHERE Id=:Id`, job); err != nil { return nil, errors.Wrapf(err, "failed to update Job with id=%s", id) } @@ -116,7 +130,7 @@ func (jss SqlJobStore) UpdateStatusOptimistically(id string, currentStatus strin return false, errors.Wrap(err, "job_tosql") } - sqlResult, err := jss.GetMaster().Exec(query, args...) + sqlResult, err := jss.GetMasterX().Exec(query, args...) if err != nil { return false, errors.Wrapf(err, "failed to update Job with id=%s", id) } @@ -139,14 +153,14 @@ func (jss SqlJobStore) Get(id string) (*model.Job, error) { if err != nil { return nil, errors.Wrap(err, "job_tosql") } - var status *model.Job - if err = jss.GetReplica().SelectOne(&status, query, args...); err != nil { + var status model.Job + if err = jss.GetReplicaX().Get(&status, query, args...); err != nil { if err == sql.ErrNoRows { return nil, store.NewErrNotFound("Job", id) } return nil, errors.Wrapf(err, "failed to get Job with id=%s", id) } - return status, nil + return &status, nil } func (jss SqlJobStore) GetAllPage(offset int, limit int) ([]*model.Job, error) { @@ -160,8 +174,8 @@ func (jss SqlJobStore) GetAllPage(offset int, limit int) ([]*model.Job, error) { return nil, errors.Wrap(err, "job_tosql") } - var statuses []*model.Job - if _, err = jss.GetReplica().Select(&statuses, query, args...); err != nil { + statuses := []*model.Job{} + if err = jss.GetReplicaX().Select(&statuses, query, args...); err != nil { return nil, errors.Wrap(err, "failed to find Jobs") } return statuses, nil @@ -180,7 +194,7 @@ func (jss SqlJobStore) GetAllByTypesPage(jobTypes []string, offset int, limit in } var jobs []*model.Job - if _, err = jss.GetReplica().Select(&jobs, query, args...); err != nil { + if err = jss.GetReplicaX().Select(&jobs, query, args...); err != nil { return nil, errors.Wrapf(err, "failed to find Jobs with types") } return jobs, nil @@ -195,8 +209,8 @@ func (jss SqlJobStore) GetAllByType(jobType string) ([]*model.Job, error) { if err != nil { return nil, errors.Wrap(err, "job_tosql") } - var statuses []*model.Job - if _, err = jss.GetReplica().Select(&statuses, query, args...); err != nil { + statuses := []*model.Job{} + if err = jss.GetReplicaX().Select(&statuses, query, args...); err != nil { return nil, errors.Wrapf(err, "failed to find Jobs with type=%s", jobType) } return statuses, nil @@ -214,15 +228,15 @@ func (jss SqlJobStore) GetAllByTypePage(jobType string, offset int, limit int) ( return nil, errors.Wrap(err, "job_tosql") } - var statuses []*model.Job - if _, err = jss.GetReplica().Select(&statuses, query, args...); err != nil { + statuses := []*model.Job{} + if err = jss.GetReplicaX().Select(&statuses, query, args...); err != nil { return nil, errors.Wrapf(err, "failed to find Jobs with type=%s", jobType) } return statuses, nil } func (jss SqlJobStore) GetAllByStatus(status string) ([]*model.Job, error) { - var statuses []*model.Job + statuses := []*model.Job{} query, args, err := jss.getQueryBuilder(). Select("*"). From("Jobs"). @@ -232,7 +246,7 @@ func (jss SqlJobStore) GetAllByStatus(status string) ([]*model.Job, error) { return nil, errors.Wrap(err, "job_tosql") } - if _, err = jss.GetReplica().Select(&statuses, query, args...); err != nil { + if err = jss.GetReplicaX().Select(&statuses, query, args...); err != nil { return nil, errors.Wrapf(err, "failed to find Jobs with status=%s", status) } return statuses, nil @@ -253,14 +267,14 @@ func (jss SqlJobStore) GetNewestJobByStatusesAndType(status []string, jobType st return nil, errors.Wrap(err, "job_tosql") } - var job *model.Job - if err = jss.GetReplica().SelectOne(&job, query, args...); err != nil { + var job model.Job + if err = jss.GetReplicaX().Get(&job, query, args...); err != nil { if err == sql.ErrNoRows { return nil, store.NewErrNotFound("Job", fmt.Sprintf("=<%s, %s>", strings.Join(status, ","), jobType)) } return nil, errors.Wrapf(err, "failed to find Job with statuses=%s and type=%s", strings.Join(status, ","), jobType) } - return job, nil + return &job, nil } func (jss SqlJobStore) GetCountByStatusAndType(status string, jobType string) (int64, error) { @@ -271,7 +285,9 @@ func (jss SqlJobStore) GetCountByStatusAndType(status string, jobType string) (i if err != nil { return 0, errors.Wrap(err, "job_tosql") } - count, err := jss.GetReplica().SelectInt(query, args...) + + var count int64 + err = jss.GetReplicaX().Get(&count, query, args...) if err != nil { return int64(0), errors.Wrapf(err, "failed to count Jobs with status=%s and type=%s", status, jobType) } @@ -286,7 +302,7 @@ func (jss SqlJobStore) Delete(id string) (string, error) { return "", errors.Wrap(err, "job_tosql") } - if _, err = jss.GetMaster().Exec(query, args...); err != nil { + if _, err = jss.GetMasterX().Exec(query, args...); err != nil { return "", errors.Wrapf(err, "failed to delete Job with id=%s", id) } return id, nil