From 1c1a445a3ed1cf692a5ea2594321ca99a7660707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa=20Montoro?= Date: Thu, 29 Jan 2026 21:14:56 +0100 Subject: [PATCH] MM-67380: COALESCE Drafts.Type to the empty string if NULL (#35109) When the Type column was added to the Drafts table, it did not add a DEFAULT value, so we need to handle the NULL values for the pre-existing rows. Co-authored-by: Mattermost Build --- server/channels/store/sqlstore/draft_store.go | 2 +- .../channels/store/storetest/draft_store.go | 89 ++++++++++--------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/server/channels/store/sqlstore/draft_store.go b/server/channels/store/sqlstore/draft_store.go index 8b7e57fe5f6..58a502fe0b3 100644 --- a/server/channels/store/sqlstore/draft_store.go +++ b/server/channels/store/sqlstore/draft_store.go @@ -129,7 +129,7 @@ func (s *SqlDraftStore) GetDraftsForUser(userID, teamID string) ([]*model.Draft, "Drafts.FileIds", "Drafts.Props", "Drafts.Priority", - "Drafts.Type", + "COALESCE(Drafts.Type, '') AS Type", ). From("Drafts"). InnerJoin("ChannelMembers ON ChannelMembers.ChannelId = Drafts.ChannelId"). diff --git a/server/channels/store/storetest/draft_store.go b/server/channels/store/storetest/draft_store.go index e20d2ce1c08..9e0cb73e4b7 100644 --- a/server/channels/store/storetest/draft_store.go +++ b/server/channels/store/storetest/draft_store.go @@ -369,56 +369,63 @@ func testGetDraftsForUser(t *testing.T, rctx request.CTX, ss store.Store) { Id: model.NewId(), } - channel := &model.Channel{ - Id: model.NewId(), + newDraftForUser := func(t *testing.T, user *model.User) *model.Draft { + t.Helper() + + channel := &model.Channel{ + Id: model.NewId(), + } + member := &model.ChannelMember{ + ChannelId: channel.Id, + UserId: user.Id, + NotifyProps: model.GetDefaultChannelNotifyProps(), + } + _, err := ss.Channel().SaveMember(rctx, member) + require.NoError(t, err) + + draft := &model.Draft{ + UserId: user.Id, + ChannelId: channel.Id, + Message: "draft post", + } + insertedDraft, err := ss.Draft().Upsert(draft) + require.NoError(t, err) + + return insertedDraft } - channel2 := &model.Channel{ - Id: model.NewId(), - } - - member1 := &model.ChannelMember{ - ChannelId: channel.Id, - UserId: user.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - } - - member2 := &model.ChannelMember{ - ChannelId: channel2.Id, - UserId: user.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - } - - _, err := ss.Channel().SaveMember(rctx, member1) - require.NoError(t, err) - - _, err = ss.Channel().SaveMember(rctx, member2) - require.NoError(t, err) - - draft1 := &model.Draft{ - UserId: user.Id, - ChannelId: channel.Id, - Message: "draft1", - } - - draft2 := &model.Draft{ - UserId: user.Id, - ChannelId: channel2.Id, - Message: "draft2", - } - - _, err = ss.Draft().Upsert(draft1) - require.NoError(t, err) - - _, err = ss.Draft().Upsert(draft2) - require.NoError(t, err) t.Run("get drafts", func(t *testing.T) { + t.Cleanup(func() { clearDrafts(t, rctx, ss) }) + + draft1 := newDraftForUser(t, user) + draft2 := newDraftForUser(t, user) + draftResp, err := ss.Draft().GetDraftsForUser(user.Id, "") assert.NoError(t, err) assert.Len(t, draftResp, 2) assert.ElementsMatch(t, []*model.Draft{draft1, draft2}, draftResp) }) + + t.Run("get drafts with Type NULL", func(t *testing.T) { + t.Cleanup(func() { clearDrafts(t, rctx, ss) }) + + draft := newDraftForUser(t, user) + + // Draft().Upsert() correctly handles empty types, so we need to + // manually set Type to NULL + query := "UPDATE Drafts SET Type = NULL WHERE UserId = $1" + _, err := ss.GetInternalMasterDB().Exec(query, user.Id) + require.NoError(t, err) + + draftResp, err := ss.Draft().GetDraftsForUser(user.Id, "") + assert.NoError(t, err) + assert.Len(t, draftResp, 1) + + assert.ElementsMatch(t, []*model.Draft{draft}, draftResp) + + clearDrafts(t, rctx, ss) + }) } func clearDrafts(t *testing.T, rctx request.CTX, ss store.Store) {