diff --git a/store/sqlstore/adapters.go b/store/sqlstore/adapters.go index b19b60e27d..35aa1aedcf 100644 --- a/store/sqlstore/adapters.go +++ b/store/sqlstore/adapters.go @@ -43,6 +43,18 @@ func (a jsonArray) Value() (driver.Value, error) { return out.Bytes(), nil } +type jsonStringVal string + +func (str jsonStringVal) Value() (driver.Value, error) { + return strconv.Quote(string(str)), nil +} + +type jsonKeyPath string + +func (str jsonKeyPath) Value() (driver.Value, error) { + return "{" + string(str) + "}", nil +} + type TraceOnAdapter struct{} func (t *TraceOnAdapter) Printf(format string, v ...interface{}) { diff --git a/store/sqlstore/post_store.go b/store/sqlstore/post_store.go index 9b76f6164c..7758fc5973 100644 --- a/store/sqlstore/post_store.go +++ b/store/sqlstore/post_store.go @@ -658,30 +658,42 @@ func (s *SqlPostStore) GetEtag(channelId string, allowFromCache, collapsedThread return result } -func (s *SqlPostStore) Delete(postId string, time int64, deleteByID string) error { - var post model.Post - err := s.GetReplica().SelectOne(&post, "SELECT * FROM Posts WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": postId}) - if err != nil { - if err == sql.ErrNoRows { - return store.NewErrNotFound("Post", postId) - } - - return errors.Wrapf(err, "failed to delete Post with id=%s", postId) +func (s *SqlPostStore) Delete(postID string, time int64, deleteByID string) error { + var err error + if s.DriverName() == model.DatabaseDriverPostgres { + _, err = s.GetMaster().Exec(`UPDATE Posts + SET DeleteAt = $1, + UpdateAt = $1, + Props = jsonb_set(Props, $2, $3) + WHERE Id = $4 OR RootId = $4`, time, jsonKeyPath(model.PostPropsDeleteBy), jsonStringVal(deleteByID), postID) + } else { + _, err = s.GetMaster().Exec(`UPDATE Posts + SET DeleteAt = ?, + UpdateAt = ?, + Props = JSON_SET(Props, ?, ?) + Where Id = ? OR RootId = ?`, time, time, "$."+model.PostPropsDeleteBy, deleteByID, postID, postID) } - post.AddProp(model.PostPropsDeleteBy, deleteByID) - - _, err = s.GetMaster().Exec("UPDATE Posts SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt, Props = :Props WHERE Id = :Id OR RootId = :RootId", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": postId, "RootId": postId, "Props": model.StringInterfaceToJson(post.GetProps())}) if err != nil { return errors.Wrap(err, "failed to update Posts") } - return s.cleanupThreads(post.Id, post.RootId, false) + // TODO: change this to later delete thread directly from postID + rootID, err := s.GetReplica().SelectStr("SELECT RootId FROM Posts WHERE Id = :Id", map[string]interface{}{"Id": postID}) + if err != nil { + if err == sql.ErrNoRows { + return store.NewErrNotFound("Post", postID) + } + + return errors.Wrapf(err, "failed to delete Post with id=%s", postID) + } + + return s.cleanupThreads(postID, rootID, false) } func (s *SqlPostStore) permanentDelete(postId string) error { var post model.Post - err := s.GetReplica().SelectOne(&post, "SELECT * FROM Posts WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": postId}) + err := s.GetReplica().SelectOne(&post, "SELECT * FROM Posts WHERE Id = :Id", map[string]interface{}{"Id": postId}) if err != nil && err != sql.ErrNoRows { return errors.Wrapf(err, "failed to get Post with id=%s", postId) } diff --git a/store/storetest/post_store.go b/store/storetest/post_store.go index a5204b77be..b5697b7611 100644 --- a/store/storetest/post_store.go +++ b/store/storetest/post_store.go @@ -616,7 +616,7 @@ func testPostStoreDelete(t *testing.T, ss store.Store) { o1 := &model.Post{} o1.ChannelId = model.NewId() o1.UserId = model.NewId() - o1.Message = "zz" + model.NewId() + "b" + o1.Message = model.NewRandomString(10) deleteByID := model.NewId() etag1 := ss.Post().GetEtag(o1.ChannelId, false, false)