You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2021/06/28 10:29:39 UTC

[james-project] branch master updated (c0c7989 -> 8a827e7)

This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.


    from c0c7989  [REFATORING] Use AddressList::flatten where relevant
     new ade4a75  JAMES-3516 Add threadId column to messageIdTable and imapUidTable
     new d4e5553  JAMES-3516 Modify Cassandra migration document following adding threadId column
     new 6b1bdc0  JAMES-3516 Enable reading and writing to threadId column
     new 8a827e7  JAMES-3516 Add threadId to ComposedMessageIdWithMetaData

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../model/ComposedMessageIdWithMetaData.java       | 23 +++++++++--
 .../model/ComposedMessageIdWithMetaDataTest.java   | 23 +++++++++--
 .../cassandra/mail/CassandraMessageIdDAO.java      | 20 ++++++++-
 .../cassandra/mail/CassandraMessageIdMapper.java   |  4 +-
 .../mail/CassandraMessageIdToImapUidDAO.java       | 20 ++++++++-
 .../cassandra/mail/CassandraMessageMapper.java     |  2 +
 .../cassandra/modules/CassandraMessageModule.java  |  2 +
 .../cassandra/table/CassandraMessageIdTable.java   |  4 +-
 .../cassandra/table/MessageIdToImapUid.java        |  5 ++-
 .../mail/CassandraIndexTableHandlerTest.java       | 22 ++++++----
 .../cassandra/mail/CassandraMessageDAOTest.java    |  2 +
 .../cassandra/mail/CassandraMessageDAOV3Test.java  |  2 +
 .../cassandra/mail/CassandraMessageIdDAOTest.java  | 47 ++++++++++++++++++++++
 .../mail/CassandraMessageIdMapperTest.java         |  4 +-
 .../mail/CassandraMessageIdToImapUidDAOTest.java   | 33 +++++++++++++++
 .../cassandra/mail/CassandraMessageMapperTest.java |  8 ++--
 .../task/RecomputeMailboxCountersServiceTest.java  |  5 ++-
 .../SolveMessageInconsistenciesServiceTest.java    | 23 ++++++-----
 .../model/openjpa/AbstractJPAMailboxMessage.java   |  1 +
 .../maildir/mail/model/MaildirMailboxMessage.java  |  1 +
 .../inmemory/mail/InMemoryMessageIdMapper.java     |  3 +-
 .../james/mailbox/store/mail/MessageMapper.java    |  3 +-
 .../mail/model/impl/SimpleMailboxMessage.java      |  1 +
 src/site/xdoc/server/config-cassandra.xml          |  6 +++
 upgrade-instructions.md                            | 17 ++++++++
 25 files changed, 242 insertions(+), 39 deletions(-)

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 01/04: JAMES-3516 Add threadId column to messageIdTable and imapUidTable

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit ade4a75e8805cdf978dfa3491ef421c136e028d7
Author: quanth <hq...@linagora.com>
AuthorDate: Mon Jun 21 11:42:08 2021 +0700

    JAMES-3516 Add threadId column to messageIdTable and imapUidTable
---
 .../james/mailbox/cassandra/modules/CassandraMessageModule.java       | 2 ++
 .../apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java | 4 +++-
 .../org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java  | 4 +++-
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java
index 6b51570..92d6306 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java
@@ -55,6 +55,7 @@ public interface CassandraMessageModule {
             .addPartitionKey(CassandraMessageIds.MAILBOX_ID, timeuuid())
             .addClusteringColumn(CassandraMessageIds.IMAP_UID, bigint())
             .addColumn(CassandraMessageIds.MESSAGE_ID, timeuuid())
+            .addColumn(CassandraMessageIdTable.THREAD_ID, timeuuid())
             .addColumn(CassandraMessageIdTable.MOD_SEQ, bigint())
             .addColumn(Flag.ANSWERED, cboolean())
             .addColumn(Flag.DELETED, cboolean())
@@ -75,6 +76,7 @@ public interface CassandraMessageModule {
             .addPartitionKey(CassandraMessageIds.MESSAGE_ID, timeuuid())
             .addClusteringColumn(CassandraMessageIds.MAILBOX_ID, timeuuid())
             .addClusteringColumn(CassandraMessageIds.IMAP_UID, bigint())
+            .addColumn(MessageIdToImapUid.THREAD_ID, timeuuid())
             .addColumn(MessageIdToImapUid.MOD_SEQ, bigint())
             .addColumn(Flag.ANSWERED, cboolean())
             .addColumn(Flag.DELETED, cboolean())
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java
index 9ca58fa..a3ad5e6 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java
@@ -29,6 +29,8 @@ public interface CassandraMessageIdTable {
 
     String MOD_SEQ = "modSeq";
 
-    String[] FIELDS = { MESSAGE_ID, MAILBOX_ID, IMAP_UID, MOD_SEQ,
+    String THREAD_ID = "threadId";
+
+    String[] FIELDS = { MESSAGE_ID, MAILBOX_ID, IMAP_UID, THREAD_ID, MOD_SEQ,
             Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS};
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java
index 4e7fc79..8294117 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java
@@ -32,6 +32,8 @@ public interface MessageIdToImapUid {
     String MOD_SEQ = "modSeq";
     String MOD_SEQ_LOWERCASE = MOD_SEQ.toLowerCase(Locale.US);
 
-    String[] FIELDS = { MESSAGE_ID, MAILBOX_ID, IMAP_UID, MOD_SEQ,
+    String THREAD_ID = "threadId";
+
+    String[] FIELDS = { MESSAGE_ID, MAILBOX_ID, IMAP_UID, THREAD_ID, MOD_SEQ,
             Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS };
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 04/04: JAMES-3516 Add threadId to ComposedMessageIdWithMetaData

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 8a827e753d71c6b0a55b72b4b80c77ad9af96913
Author: quanth <hq...@linagora.com>
AuthorDate: Wed Jun 23 14:22:29 2021 +0700

    JAMES-3516 Add threadId to ComposedMessageIdWithMetaData
---
 .../model/ComposedMessageIdWithMetaData.java       | 23 +++++++++--
 .../model/ComposedMessageIdWithMetaDataTest.java   | 23 +++++++++--
 .../cassandra/mail/CassandraMessageIdDAO.java      | 16 +++++++-
 .../cassandra/mail/CassandraMessageIdMapper.java   |  4 +-
 .../mail/CassandraMessageIdToImapUidDAO.java       | 16 +++++++-
 .../cassandra/mail/CassandraMessageMapper.java     |  2 +
 .../cassandra/table/MessageIdToImapUid.java        |  1 +
 .../mail/CassandraIndexTableHandlerTest.java       | 22 ++++++----
 .../cassandra/mail/CassandraMessageDAOTest.java    |  2 +
 .../cassandra/mail/CassandraMessageDAOV3Test.java  |  2 +
 .../cassandra/mail/CassandraMessageIdDAOTest.java  | 47 ++++++++++++++++++++++
 .../mail/CassandraMessageIdToImapUidDAOTest.java   | 33 +++++++++++++++
 .../task/RecomputeMailboxCountersServiceTest.java  |  5 ++-
 .../SolveMessageInconsistenciesServiceTest.java    |  5 +++
 .../model/openjpa/AbstractJPAMailboxMessage.java   |  1 +
 .../maildir/mail/model/MaildirMailboxMessage.java  |  1 +
 .../inmemory/mail/InMemoryMessageIdMapper.java     |  3 +-
 .../james/mailbox/store/mail/MessageMapper.java    |  3 +-
 .../mail/model/impl/SimpleMailboxMessage.java      |  1 +
 19 files changed, 188 insertions(+), 22 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaData.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaData.java
index ad05c0d..c30a202 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaData.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaData.java
@@ -38,6 +38,7 @@ public class ComposedMessageIdWithMetaData {
         private ComposedMessageId composedMessageId;
         private Flags flags;
         private ModSeq modSeq;
+        private ThreadId threadId;
 
         private Builder() {
         }
@@ -57,22 +58,30 @@ public class ComposedMessageIdWithMetaData {
             return this;
         }
 
+        public Builder threadId(ThreadId threadId) {
+            this.threadId = threadId;
+            return this;
+        }
+
         public ComposedMessageIdWithMetaData build() {
             Preconditions.checkNotNull(composedMessageId, "'composedMessageId' is mandatory");
             Preconditions.checkNotNull(flags, "'flags' is mandatory");
             Preconditions.checkNotNull(modSeq, "'modSeq' is mandatory");
-            return new ComposedMessageIdWithMetaData(composedMessageId, flags, modSeq);
+            Preconditions.checkNotNull(threadId, "'threadId' is mandatory");
+            return new ComposedMessageIdWithMetaData(composedMessageId, flags, modSeq, threadId);
         }
     }
 
     private final ComposedMessageId composedMessageId;
     private final Flags flags;
     private final ModSeq modSeq;
+    private final ThreadId threadId;
 
-    public ComposedMessageIdWithMetaData(ComposedMessageId composedMessageId, Flags flags, ModSeq modSeq) {
+    public ComposedMessageIdWithMetaData(ComposedMessageId composedMessageId, Flags flags, ModSeq modSeq, ThreadId threadId) {
         this.composedMessageId = composedMessageId;
         this.flags = flags;
         this.modSeq = modSeq;
+        this.threadId = threadId;
     }
 
     public ComposedMessageId getComposedMessageId() {
@@ -87,6 +96,10 @@ public class ComposedMessageIdWithMetaData {
         return modSeq;
     }
 
+    public ThreadId getThreadId() {
+        return threadId;
+    }
+
     public boolean isMatching(MessageId messageId) {
         return getComposedMessageId().getMessageId().equals(messageId);
     }
@@ -97,14 +110,15 @@ public class ComposedMessageIdWithMetaData {
             ComposedMessageIdWithMetaData other = (ComposedMessageIdWithMetaData) o;
             return Objects.equal(composedMessageId, other.composedMessageId)
                 && Objects.equal(flags, other.flags)
-                && Objects.equal(modSeq, other.modSeq);
+                && Objects.equal(modSeq, other.modSeq)
+                && Objects.equal(threadId, other.threadId);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hashCode(composedMessageId, flags, modSeq);
+        return Objects.hashCode(composedMessageId, flags, modSeq, threadId);
     }
 
     @Override
@@ -113,6 +127,7 @@ public class ComposedMessageIdWithMetaData {
             .add("composedMessageId", composedMessageId)
             .add("flags", flags)
             .add("modSeq", modSeq)
+            .add("threadId", threadId)
             .toString();
     }
 }
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaDataTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaDataTest.java
index 77070ee..e5bcf21 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaDataTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/ComposedMessageIdWithMetaDataTest.java
@@ -36,15 +36,16 @@ class ComposedMessageIdWithMetaDataTest {
     private static final TestMessageId TEST_MESSAGE_ID = new TestMessageId("2");
     private static final MessageUid MESSAGE_UID = MessageUid.of(3);
     private static final ComposedMessageId COMPOSED_MESSAGE_ID = new ComposedMessageId(TEST_ID, TEST_MESSAGE_ID, MESSAGE_UID);
+    private static final ThreadId THREAD_ID = ThreadId.fromBaseMessageId(TEST_MESSAGE_ID);
 
     @Test
-    void buildShoudThrownWhenComposedMessageIdIsNull() {
+    void buildShouldThrownWhenComposedMessageIdIsNull() {
         assertThatThrownBy(() -> ComposedMessageIdWithMetaData.builder().build())
             .isInstanceOf(NullPointerException.class);
     }
 
     @Test
-    void buildShoudThrownWhenFlagsIsNull() {
+    void buildShouldThrownWhenFlagsIsNull() {
         assertThatThrownBy(() -> ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(COMPOSED_MESSAGE_ID)
                 .build())
@@ -52,7 +53,7 @@ class ComposedMessageIdWithMetaDataTest {
     }
 
     @Test
-    void buildShoudThrownWhenModSeqIsNull() {
+    void buildShouldThrownWhenModSeqIsNull() {
         assertThatThrownBy(() -> ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(COMPOSED_MESSAGE_ID)
                 .flags(new Flags())
@@ -61,7 +62,17 @@ class ComposedMessageIdWithMetaDataTest {
     }
 
     @Test
-    void buildShoudWork() {
+    void buildShouldThrownWhenThreadIdIsNull() {
+        assertThatThrownBy(() -> ComposedMessageIdWithMetaData.builder()
+                .composedMessageId(COMPOSED_MESSAGE_ID)
+                .flags(new Flags())
+                .modSeq(ModSeq.of(1))
+                .build())
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    void buildShouldWork() {
         Flags flags = new Flags(Flag.RECENT);
         ModSeq modSeq = ModSeq.of(1);
 
@@ -69,11 +80,13 @@ class ComposedMessageIdWithMetaDataTest {
             .composedMessageId(COMPOSED_MESSAGE_ID)
             .flags(flags)
             .modSeq(modSeq)
+            .threadId(THREAD_ID)
             .build();
 
         assertThat(composedMessageIdWithMetaData.getComposedMessageId()).isEqualTo(COMPOSED_MESSAGE_ID);
         assertThat(composedMessageIdWithMetaData.getFlags()).isEqualTo(flags);
         assertThat(composedMessageIdWithMetaData.getModSeq()).isEqualTo(modSeq);
+        assertThat(composedMessageIdWithMetaData.getThreadId()).isEqualTo(THREAD_ID);
     }
 
     @Test
@@ -82,6 +95,7 @@ class ComposedMessageIdWithMetaDataTest {
                 .composedMessageId(new ComposedMessageId(TEST_ID, TEST_MESSAGE_ID, MESSAGE_UID))
                 .flags(new Flags(Flag.RECENT))
                 .modSeq(ModSeq.of(1))
+                .threadId(THREAD_ID)
                 .build();
 
         assertThat(composedMessageIdWithMetaData.isMatching(TEST_MESSAGE_ID)).isTrue();
@@ -93,6 +107,7 @@ class ComposedMessageIdWithMetaDataTest {
                 .composedMessageId(COMPOSED_MESSAGE_ID)
                 .flags(new Flags(Flag.RECENT))
                 .modSeq(ModSeq.of(1))
+                .threadId(THREAD_ID)
                 .build();
 
         assertThat(composedMessageIdWithMetaData.isMatching(new TestMessageId("3"))).isFalse();
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
index 5714e36..aff977a 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
@@ -45,9 +45,11 @@ import static org.apache.james.mailbox.cassandra.table.Flag.USER;
 import static org.apache.james.mailbox.cassandra.table.Flag.USER_FLAGS;
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ;
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ_LOWERCASE;
+import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.THREAD_ID_LOWERCASE;
 import static org.apache.james.util.ReactorUtils.publishIfPresent;
 
 import java.util.Optional;
+import java.util.UUID;
 
 import javax.inject.Inject;
 import javax.mail.Flags;
@@ -61,7 +63,9 @@ import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId.Factory;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
+import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.util.streams.Limit;
 
 import com.datastax.driver.core.PreparedStatement;
@@ -349,13 +353,23 @@ public class CassandraMessageIdDAO {
                 .subscribe();
             return Optional.empty();
         }
+        MessageId messageId = messageIdFactory.of(row.getUUID(MESSAGE_ID_LOWERCASE));
         return Optional.of(ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(
                         CassandraId.of(row.getUUID(MAILBOX_ID_LOWERCASE)),
-                        messageIdFactory.of(row.getUUID(MESSAGE_ID_LOWERCASE)),
+                        messageId,
                         MessageUid.of(row.getLong(IMAP_UID))))
                 .flags(FlagsExtractor.getFlags(row))
                 .modSeq(ModSeq.of(row.getLong(MOD_SEQ_LOWERCASE)))
+                .threadId(getThreadIdFromRow(row, messageId))
                 .build());
     }
+
+    private ThreadId getThreadIdFromRow(Row row, MessageId messageId) {
+        UUID threadIdUUID = row.getUUID(THREAD_ID_LOWERCASE);
+        if (threadIdUUID == null) {
+            return ThreadId.fromBaseMessageId(messageId);
+        }
+        return ThreadId.fromBaseMessageId(messageIdFactory.of(threadIdUUID));
+    }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
index 84407d8..91bafd5 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
@@ -202,6 +202,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
             .composedMessageId(composedMessageId)
             .flags(mailboxMessage.createFlags())
             .modSeq(mailboxMessage.getModSeq())
+            .threadId(mailboxMessage.getThreadId())
             .build();
     }
 
@@ -313,7 +314,8 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
                 .map(modSeq -> new ComposedMessageIdWithMetaData(
                     oldComposedId.getComposedMessageId(),
                     newFlags,
-                    modSeq))
+                    modSeq,
+                    oldComposedId.getThreadId()))
             .flatMap(newComposedId -> updateFlags(oldComposedId, newComposedId));
         }
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
index 98a58ef..4ff6d01 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
@@ -43,8 +43,10 @@ import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SE
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ_LOWERCASE;
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.THREAD_ID;
+import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.THREAD_ID_LOWERCASE;
 
 import java.util.Optional;
+import java.util.UUID;
 
 import javax.inject.Inject;
 import javax.mail.Flags;
@@ -61,6 +63,8 @@ import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId.Factory;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 
 import com.datastax.driver.core.BoundStatement;
 import com.datastax.driver.core.PreparedStatement;
@@ -245,16 +249,26 @@ public class CassandraMessageIdToImapUidDAO {
     }
 
     private ComposedMessageIdWithMetaData toComposedMessageIdWithMetadata(Row row) {
+        MessageId messageId = messageIdFactory.of(row.getUUID(MESSAGE_ID_LOWERCASE));
         return ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(
                     CassandraId.of(row.getUUID(MAILBOX_ID_LOWERCASE)),
-                    messageIdFactory.of(row.getUUID(MESSAGE_ID_LOWERCASE)),
+                    messageId,
                     MessageUid.of(row.getLong(IMAP_UID))))
                 .flags(FlagsExtractor.getFlags(row))
                 .modSeq(ModSeq.of(row.getLong(MOD_SEQ_LOWERCASE)))
+                .threadId(getThreadIdFromRow(row, messageId))
                 .build();
     }
 
+    private ThreadId getThreadIdFromRow(Row row, MessageId messageId) {
+        UUID threadIdUUID = row.getUUID(THREAD_ID_LOWERCASE);
+        if (threadIdUUID == null) {
+            return ThreadId.fromBaseMessageId(messageId);
+        }
+        return ThreadId.fromBaseMessageId(messageIdFactory.of(threadIdUUID));
+    }
+
     private Statement selectStatement(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
         return mailboxId
             .map(cassandraId -> select.bind()
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index 7bf43d1..1d464fc 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -534,6 +534,7 @@ public class CassandraMessageMapper implements MessageMapper {
                 .composedMessageId(new ComposedMessageId(mailboxId, message.getMessageId(), message.getUid()))
                 .flags(message.createFlags())
                 .modSeq(message.getModSeq())
+                .threadId(message.getThreadId())
                 .build();
         return composedMessageIdWithMetaData;
     }
@@ -587,6 +588,7 @@ public class CassandraMessageMapper implements MessageMapper {
                 .composedMessageId(oldMetadata.getComposedMessageId())
                 .modSeq(newModSeq)
                 .flags(newFlags)
+                .threadId(oldMetadata.getThreadId())
                 .build();
         return imapUidDAO.updateMetadata(newMetadata, oldMetadata.getModSeq())
             .flatMap(success -> {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java
index 8294117..df1dd3c 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/MessageIdToImapUid.java
@@ -33,6 +33,7 @@ public interface MessageIdToImapUid {
     String MOD_SEQ_LOWERCASE = MOD_SEQ.toLowerCase(Locale.US);
 
     String THREAD_ID = "threadId";
+    String THREAD_ID_LOWERCASE = THREAD_ID.toLowerCase(Locale.US);
 
     String[] FIELDS = { MESSAGE_ID, MAILBOX_ID, IMAP_UID, THREAD_ID, MOD_SEQ,
             Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS };
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java
index beb08d5..5151916 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java
@@ -45,6 +45,7 @@ import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.model.UidValidity;
 import org.apache.james.mailbox.model.UpdatedFlags;
 import org.apache.james.mailbox.store.MessageBuilder;
@@ -198,7 +199,8 @@ class CassandraIndexTableHandlerTest {
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(Flags.Flag.RECENT),
-                MODSEQ),
+                MODSEQ,
+                ThreadId.fromBaseMessageId(CASSANDRA_MESSAGE_ID)),
             MAILBOX_ID).block();
 
         Long actual = mailboxCounterDAO.countMessagesInMailbox(mailbox).block();
@@ -215,7 +217,8 @@ class CassandraIndexTableHandlerTest {
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(),
-                MODSEQ),
+                MODSEQ,
+                ThreadId.fromBaseMessageId(CASSANDRA_MESSAGE_ID)),
             MAILBOX_ID).block();
 
         Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
@@ -232,7 +235,8 @@ class CassandraIndexTableHandlerTest {
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(Flags.Flag.SEEN),
-                MODSEQ),
+                MODSEQ,
+                ThreadId.fromBaseMessageId(CASSANDRA_MESSAGE_ID)),
             MAILBOX_ID).block();
 
         Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
@@ -249,7 +253,8 @@ class CassandraIndexTableHandlerTest {
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(Flags.Flag.RECENT),
-                MODSEQ),
+                MODSEQ,
+                ThreadId.fromBaseMessageId(CASSANDRA_MESSAGE_ID)),
             MAILBOX_ID).block();
 
         assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
@@ -269,7 +274,8 @@ class CassandraIndexTableHandlerTest {
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(),
-                MODSEQ),
+                MODSEQ,
+                ThreadId.fromBaseMessageId(CASSANDRA_MESSAGE_ID)),
             MAILBOX_ID).block();
 
         assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
@@ -287,7 +293,8 @@ class CassandraIndexTableHandlerTest {
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(Flags.Flag.DELETED),
-                MODSEQ),
+                MODSEQ,
+                ThreadId.fromBaseMessageId(CASSANDRA_MESSAGE_ID)),
             MAILBOX_ID).block();
 
         assertThat(
@@ -656,7 +663,8 @@ class CassandraIndexTableHandlerTest {
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
             new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
             new Flags(),
-            MODSEQ), MAILBOX_ID).block();
+            MODSEQ,
+            ThreadId.fromBaseMessageId(CASSANDRA_MESSAGE_ID)), MAILBOX_ID).block();
 
         Boolean actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).hasElement().block();
         assertThat(actual).isFalse();
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
index 7003aae..b80822e 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
@@ -47,6 +47,7 @@ import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.MessageAttachmentMetadata;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
@@ -102,6 +103,7 @@ class CassandraMessageDAOTest {
                 .composedMessageId(new ComposedMessageId(MAILBOX_ID, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java
index 7ef00ea..21c9f5a 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java
@@ -47,6 +47,7 @@ import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.MessageAttachmentMetadata;
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
@@ -100,6 +101,7 @@ class CassandraMessageDAOV3Test {
                 .composedMessageId(new ComposedMessageId(MAILBOX_ID, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
index 2ae675e..26d5580 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
@@ -37,6 +37,7 @@ import org.apache.james.mailbox.cassandra.modules.CassandraMessageModule;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.util.streams.Limit;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -76,6 +77,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -94,6 +96,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -103,6 +106,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags(org.apache.james.mailbox.cassandra.table.Flag.ANSWERED))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -122,11 +126,13 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build()),
             testee.insert(ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId2))
                 .build()))
         .blockLast();
 
@@ -148,6 +154,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.insert(composedMessageIdWithMetaData).block();
 
@@ -166,6 +173,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -173,6 +181,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -191,6 +200,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -198,6 +208,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.ANSWERED))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -216,6 +227,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -223,6 +235,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.DELETED))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -241,6 +254,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -248,6 +262,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.DRAFT))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -266,6 +281,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -273,6 +289,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.FLAGGED))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -291,6 +308,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -298,6 +316,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.RECENT))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -316,6 +335,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -323,6 +343,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.SEEN))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -341,6 +362,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -348,6 +370,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.USER))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -366,6 +389,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -375,6 +399,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(flags)
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId).block();
 
@@ -391,6 +416,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.insert(composedMessageIdWithMetaData).block();
 
@@ -411,11 +437,13 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData2 = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         Flux.merge(testee.insert(composedMessageIdWithMetaData),
                 testee.insert(composedMessageIdWithMetaData2))
@@ -437,11 +465,13 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData2 = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId2))
                 .build();
         Flux.merge(testee.insert(composedMessageIdWithMetaData),
                 testee.insert(composedMessageIdWithMetaData2))
@@ -465,17 +495,20 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId2))
                 .build();
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData2 = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId3, messageUid3))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId3))
                 .build();
         Flux.merge(testee.insert(
                 ComposedMessageIdWithMetaData.builder()
                     .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId))
                     .build()),
                 testee.insert(composedMessageIdWithMetaData),
                 testee.insert(composedMessageIdWithMetaData2))
@@ -499,17 +532,20 @@ class CassandraMessageIdDAOTest {
             .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
             .flags(new Flags())
             .modSeq(ModSeq.of(1))
+            .threadId(ThreadId.fromBaseMessageId(messageId2))
             .build();
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData2 = ComposedMessageIdWithMetaData.builder()
             .composedMessageId(new ComposedMessageId(mailboxId, messageId3, messageUid3))
             .flags(new Flags())
             .modSeq(ModSeq.of(1))
+            .threadId(ThreadId.fromBaseMessageId(messageId3))
             .build();
         Flux.merge(testee.insert(
             ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build()),
             testee.insert(composedMessageIdWithMetaData),
             testee.insert(composedMessageIdWithMetaData2))
@@ -535,6 +571,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -542,12 +579,14 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId2))
                 .build();
 
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData2 = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId3, messageUid3))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId3))
                 .build();
         Flux.merge(testee.insert(composedMessageIdWithMetaData),
                 testee.insert(composedMessageIdWithMetaData2),
@@ -555,6 +594,7 @@ class CassandraMessageIdDAOTest {
                     .composedMessageId(new ComposedMessageId(mailboxId, messageId4, messageUid4))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId4))
                     .build()))
         .blockLast();
 
@@ -578,6 +618,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
             .build())
             .block();
 
@@ -585,12 +626,14 @@ class CassandraMessageIdDAOTest {
             .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
             .flags(new Flags())
             .modSeq(ModSeq.of(1))
+            .threadId(ThreadId.fromBaseMessageId(messageId2))
             .build();
 
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData2 = ComposedMessageIdWithMetaData.builder()
             .composedMessageId(new ComposedMessageId(mailboxId, messageId3, messageUid3))
             .flags(new Flags())
             .modSeq(ModSeq.of(1))
+            .threadId(ThreadId.fromBaseMessageId(messageId3))
             .build();
         Flux.merge(testee.insert(composedMessageIdWithMetaData),
             testee.insert(composedMessageIdWithMetaData2),
@@ -598,6 +641,7 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId4, messageUid4))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId4))
                 .build()))
             .blockLast();
 
@@ -619,18 +663,21 @@ class CassandraMessageIdDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId2, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId2))
                 .build();
         Flux.merge(testee.insert(
                 ComposedMessageIdWithMetaData.builder()
                     .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId))
                     .build()),
                 testee.insert(composedMessageIdWithMetaData),
                 testee.insert(ComposedMessageIdWithMetaData.builder()
                     .composedMessageId(new ComposedMessageId(mailboxId, messageId3, messageUid3))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId3))
                     .build()))
         .blockLast();
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
index 6abb4b6..0a376b7 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
@@ -38,6 +38,7 @@ import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.modules.CassandraMessageModule;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
+import org.apache.james.mailbox.model.ThreadId;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -83,6 +84,7 @@ class CassandraMessageIdToImapUidDAOTest {
                     .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId))
                     .build())
                 .block();
 
@@ -104,11 +106,13 @@ class CassandraMessageIdToImapUidDAOTest {
                     .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId))
                     .build()),
             testee.insert(ComposedMessageIdWithMetaData.builder()
                     .composedMessageId(new ComposedMessageId(mailboxId2, messageId, messageUid2))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId))
                     .build()))
         .blockLast();
 
@@ -118,6 +122,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId2, messageId, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.empty()).collectList().block();
         assertThat(messages).containsOnly(expectedComposedMessageId);
@@ -133,6 +138,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -140,6 +146,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
         assertThat(messages).containsOnly(expectedComposedMessageId);
@@ -155,6 +162,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.insert(composedMessageIdWithFlags).block();
 
@@ -173,6 +181,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.insert(composedMessageIdWithFlags).block();
 
@@ -192,6 +201,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -199,6 +209,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -217,6 +228,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -224,6 +236,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.ANSWERED))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -242,6 +255,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -249,6 +263,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.DELETED))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -267,6 +282,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -274,6 +290,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.DRAFT))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -292,6 +309,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -299,6 +317,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.FLAGGED))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -317,6 +336,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -324,6 +344,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.RECENT))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -342,6 +363,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -349,6 +371,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.SEEN))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         assertThat(testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block())
             .isTrue();
@@ -368,6 +391,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -375,6 +399,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags(Flag.USER))
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -393,6 +418,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -402,6 +428,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(composedMessageId)
                 .flags(flags)
                 .modSeq(ModSeq.of(2))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         testee.updateMetadata(expectedComposedMessageId, ModSeq.of(1)).block();
 
@@ -418,6 +445,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build())
             .block();
 
@@ -425,6 +453,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
 
@@ -443,11 +472,13 @@ class CassandraMessageIdToImapUidDAOTest {
                     .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId))
                     .build()),
                 testee.insert(ComposedMessageIdWithMetaData.builder()
                     .composedMessageId(new ComposedMessageId(mailboxId2, messageId, messageUid2))
                     .flags(new Flags())
                     .modSeq(ModSeq.of(1))
+                    .threadId(ThreadId.fromBaseMessageId(messageId))
                     .build()))
         .blockLast();
 
@@ -455,11 +486,13 @@ class CassandraMessageIdToImapUidDAOTest {
                 .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         ComposedMessageIdWithMetaData expectedComposedMessageId2 = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId2, messageId, messageUid2))
                 .flags(new Flags())
                 .modSeq(ModSeq.of(1))
+                .threadId(ThreadId.fromBaseMessageId(messageId))
                 .build();
         List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.empty()).collectList().block();
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java
index 0813247..2cabbc5 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java
@@ -50,6 +50,7 @@ import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxCounters;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.model.UidValidity;
 import org.apache.james.task.Task.Result;
 import org.junit.jupiter.api.BeforeEach;
@@ -67,8 +68,8 @@ class RecomputeMailboxCountersServiceTest {
     private static final CassandraMessageId.Factory MESSAGE_ID_FACTORY = new CassandraMessageId.Factory();
     private static final CassandraMessageId MESSAGE_ID_1 = MESSAGE_ID_FACTORY.fromString("40ff9e30-6022-11ea-9a94-d300cbf968c0");
     private static CassandraId CASSANDRA_ID_1 = CassandraId.of(UUID.fromString("16d681e0-6023-11ea-a7f2-0f94ad804b0d"));
-    private static final ComposedMessageIdWithMetaData METADATA_UNSEEN = new ComposedMessageIdWithMetaData(new ComposedMessageId(CASSANDRA_ID_1, MESSAGE_ID_1, MessageUid.of(45)), new Flags(), ModSeq.of(45));
-    private static final ComposedMessageIdWithMetaData METADATA_SEEN = new ComposedMessageIdWithMetaData(new ComposedMessageId(CASSANDRA_ID_1, MESSAGE_ID_1, MessageUid.of(45)), new Flags(Flags.Flag.SEEN), ModSeq.of(45));
+    private static final ComposedMessageIdWithMetaData METADATA_UNSEEN = new ComposedMessageIdWithMetaData(new ComposedMessageId(CASSANDRA_ID_1, MESSAGE_ID_1, MessageUid.of(45)), new Flags(), ModSeq.of(45), ThreadId.fromBaseMessageId(MESSAGE_ID_1));
+    private static final ComposedMessageIdWithMetaData METADATA_SEEN = new ComposedMessageIdWithMetaData(new ComposedMessageId(CASSANDRA_ID_1, MESSAGE_ID_1, MessageUid.of(45)), new Flags(Flags.Flag.SEEN), ModSeq.of(45), ThreadId.fromBaseMessageId(MESSAGE_ID_1));
     private static final Mailbox MAILBOX = new Mailbox(MAILBOX_PATH, UID_VALIDITY_1, CASSANDRA_ID_1);
 
     @RegisterExtension
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java
index d7c7c46..18d66c5 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java
@@ -45,6 +45,7 @@ import org.apache.james.mailbox.cassandra.mail.task.SolveMessageInconsistenciesS
 import org.apache.james.mailbox.cassandra.modules.CassandraMessageModule;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
+import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.task.Task;
 import org.assertj.core.api.SoftAssertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -70,24 +71,28 @@ public class SolveMessageInconsistenciesServiceTest {
         .composedMessageId(new ComposedMessageId(MAILBOX_ID, MESSAGE_ID_1, MESSAGE_UID_1))
         .modSeq(MOD_SEQ_1)
         .flags(new Flags())
+        .threadId(ThreadId.fromBaseMessageId(MESSAGE_ID_1))
         .build();
 
     private static final ComposedMessageIdWithMetaData MESSAGE_1_WITH_SEEN_FLAG = ComposedMessageIdWithMetaData.builder()
         .composedMessageId(new ComposedMessageId(MAILBOX_ID, MESSAGE_ID_1, MESSAGE_UID_1))
         .modSeq(MOD_SEQ_1)
         .flags(new Flags(Flags.Flag.SEEN))
+        .threadId(ThreadId.fromBaseMessageId(MESSAGE_ID_1))
         .build();
 
     private static final ComposedMessageIdWithMetaData MESSAGE_1_WITH_MOD_SEQ_2 = ComposedMessageIdWithMetaData.builder()
         .composedMessageId(new ComposedMessageId(MAILBOX_ID, MESSAGE_ID_1, MESSAGE_UID_1))
         .modSeq(MOD_SEQ_2)
         .flags(new Flags(Flags.Flag.SEEN))
+        .threadId(ThreadId.fromBaseMessageId(MESSAGE_ID_1))
         .build();
 
     private static final ComposedMessageIdWithMetaData MESSAGE_2 = ComposedMessageIdWithMetaData.builder()
         .composedMessageId(new ComposedMessageId(MAILBOX_ID, MESSAGE_ID_2, MESSAGE_UID_2))
         .modSeq(MOD_SEQ_2)
         .flags(new Flags())
+        .threadId(ThreadId.fromBaseMessageId(MESSAGE_ID_2))
         .build();
 
     @RegisterExtension
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java
index 6c833e2..cd9bf2f 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java
@@ -331,6 +331,7 @@ public abstract class AbstractJPAMailboxMessage implements MailboxMessage {
             .modSeq(getModSeq())
             .flags(createFlags())
             .composedMessageId(new ComposedMessageId(mailbox.getMailboxId(), getMessageId(), MessageUid.of(uid)))
+            .threadId(getThreadId())
             .build();
     }
 
diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMailboxMessage.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMailboxMessage.java
index 70ffdaa..f3f84e9 100644
--- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMailboxMessage.java
+++ b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMailboxMessage.java
@@ -78,6 +78,7 @@ public class MaildirMailboxMessage extends DelegatingMailboxMessage {
             .modSeq(modSeq)
             .flags(createFlags())
             .composedMessageId(new ComposedMessageId(mailbox.getMailboxId(), getMessageId(), uid))
+            .threadId(getThreadId())
             .build();
     }
 
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapper.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapper.java
index 569b1ae..6e13e06 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapper.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapper.java
@@ -81,7 +81,8 @@ public class InMemoryMessageIdMapper implements MessageIdMapper {
                     message.getMessageId(),
                     message.getUid()),
                 message.createFlags(),
-                message.getModSeq()));
+                message.getModSeq(),
+                message.getThreadId()));
     }
 
     @Override
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
index afce327..c844a0a 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
@@ -80,7 +80,8 @@ public interface MessageMapper extends Mapper {
                     message.getMessageId(),
                     message.getUid()),
                 message.createFlags(),
-                message.getModSeq()));
+                message.getModSeq(),
+                message.getThreadId()));
     }
 
     default Flux<MailboxMessage> findInMailboxReactive(Mailbox mailbox, MessageRange set, FetchType type, int limit) {
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java
index ef2aaba..5b5843a 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java
@@ -222,6 +222,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
             .modSeq(modSeq)
             .flags(createFlags())
             .composedMessageId(new ComposedMessageId(mailboxId, getMessageId(), uid))
+            .threadId(getThreadId())
             .build();
     }
 

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 02/04: JAMES-3516 Modify Cassandra migration document following adding threadId column

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit d4e5553a7def43bd5322895ef9b8f3a7ad31ecba
Author: quanth <hq...@linagora.com>
AuthorDate: Tue Jun 22 11:13:02 2021 +0700

    JAMES-3516 Modify Cassandra migration document following adding threadId column
---
 src/site/xdoc/server/config-cassandra.xml |  6 ++++++
 upgrade-instructions.md                   | 17 +++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/src/site/xdoc/server/config-cassandra.xml b/src/site/xdoc/server/config-cassandra.xml
index 13aa497..8ebaf09 100644
--- a/src/site/xdoc/server/config-cassandra.xml
+++ b/src/site/xdoc/server/config-cassandra.xml
@@ -319,6 +319,12 @@
 
     </subsection>
 
+    <subsection name="Adding threadId column to message metadata tables">
+
+      <p>Add threadId column to messageIdTable and imapUidTable in order to get a message's threadId.</p>
+
+    </subsection>
+
   </section>
 
 </body>
diff --git a/upgrade-instructions.md b/upgrade-instructions.md
index 46fae99..1370efc 100644
--- a/upgrade-instructions.md
+++ b/upgrade-instructions.md
@@ -19,7 +19,24 @@ Change list:
  - [Drop Cassandra schema version prior version 8](#drop-cassandra-schema-version-prior-version-8)
  - [Adopt UnboundID as a LDAP library](#adopt-unboundid-as-a-ldap-library)
  - [Review the architecture of the RabbitMQ event bus](#review-the-architecture-of-the-rabbitmq-event-bus)
+ - [Adding threadId column to message metadata tables](#adding-threadid-column-to-message-metadata-tables)
  
+### Adding threadId column to message metadata tables
+
+Date 23/06/2021
+
+JIRA: https://issues.apache.org/jira/browse/JAMES-3516
+
+Concerned product: Distributed James
+
+Add threadId column to messageIdTable and imapUidTable in order to get a message's threadId.
+
+In order to add this threadId column we advise you to run the following commands:
+```
+ALTER TABLE james_keyspace.messageIdTable ADD threadId timeuuid;
+ALTER TABLE james_keyspace.imapUidTable ADD threadId timeuuid;
+```
+
 ### Review the architecture of the RabbitMQ event bus
 
 Date 14/06/2021

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org


[james-project] 03/04: JAMES-3516 Enable reading and writing to threadId column

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 6b1bdc08bb11fb5d19cfcbde4627b1e37ad17c47
Author: quanth <hq...@linagora.com>
AuthorDate: Tue Jun 22 17:08:06 2021 +0700

    JAMES-3516 Enable reading and writing to threadId column
---
 .../mailbox/cassandra/mail/CassandraMessageIdDAO.java  |  4 ++++
 .../cassandra/mail/CassandraMessageIdToImapUidDAO.java |  4 ++++
 .../cassandra/mail/CassandraMessageIdMapperTest.java   |  4 ++--
 .../cassandra/mail/CassandraMessageMapperTest.java     |  8 ++++----
 .../task/SolveMessageInconsistenciesServiceTest.java   | 18 +++++++++---------
 5 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
index dea76ae..5714e36 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
@@ -29,6 +29,7 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.FIELDS;
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.TABLE_NAME;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.THREAD_ID;
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.IMAP_UID;
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.MAILBOX_ID;
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.MAILBOX_ID_LOWERCASE;
@@ -123,6 +124,7 @@ public class CassandraMessageIdDAO {
         return session.prepare(insertInto(TABLE_NAME)
                 .value(MAILBOX_ID, bindMarker(MAILBOX_ID))
                 .value(IMAP_UID, bindMarker(IMAP_UID))
+                .value(THREAD_ID, bindMarker(THREAD_ID))
                 .value(MOD_SEQ, bindMarker(MOD_SEQ))
                 .value(MESSAGE_ID, bindMarker(MESSAGE_ID))
                 .value(ANSWERED, bindMarker(ANSWERED))
@@ -222,10 +224,12 @@ public class CassandraMessageIdDAO {
     public Mono<Void> insert(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         Flags flags = composedMessageIdWithMetaData.getFlags();
+        ThreadId threadId = composedMessageIdWithMetaData.getThreadId();
         return cassandraAsyncExecutor.executeVoid(insert.bind()
                 .setUUID(MAILBOX_ID, ((CassandraId) composedMessageId.getMailboxId()).asUuid())
                 .setLong(IMAP_UID, composedMessageId.getUid().asLong())
                 .setUUID(MESSAGE_ID, ((CassandraMessageId) composedMessageId.getMessageId()).get())
+                .setUUID(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get())
                 .setLong(MOD_SEQ, composedMessageIdWithMetaData.getModSeq().asLong())
                 .setBool(ANSWERED, flags.contains(Flag.ANSWERED))
                 .setBool(DELETED, flags.contains(Flag.DELETED))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
index 20466fa..98a58ef 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
@@ -42,6 +42,7 @@ import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.FIELDS
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ;
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.MOD_SEQ_LOWERCASE;
 import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.TABLE_NAME;
+import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.THREAD_ID;
 
 import java.util.Optional;
 
@@ -116,6 +117,7 @@ public class CassandraMessageIdToImapUidDAO {
             .value(MESSAGE_ID, bindMarker(MESSAGE_ID))
             .value(MAILBOX_ID, bindMarker(MAILBOX_ID))
             .value(IMAP_UID, bindMarker(IMAP_UID))
+            .value(THREAD_ID, bindMarker(THREAD_ID))
             .value(MOD_SEQ, bindMarker(MOD_SEQ))
             .value(ANSWERED, bindMarker(ANSWERED))
             .value(DELETED, bindMarker(DELETED))
@@ -181,10 +183,12 @@ public class CassandraMessageIdToImapUidDAO {
     public Mono<Void> insert(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         Flags flags = composedMessageIdWithMetaData.getFlags();
+        ThreadId threadId = composedMessageIdWithMetaData.getThreadId();
         return cassandraAsyncExecutor.executeVoid(insert.bind()
                 .setUUID(MESSAGE_ID, ((CassandraMessageId) composedMessageId.getMessageId()).get())
                 .setUUID(MAILBOX_ID, ((CassandraId) composedMessageId.getMailboxId()).asUuid())
                 .setLong(IMAP_UID, composedMessageId.getUid().asLong())
+                .setUUID(THREAD_ID, ((CassandraMessageId) threadId.getBaseMessageId()).get())
                 .setLong(MOD_SEQ, composedMessageIdWithMetaData.getModSeq().asLong())
                 .setBool(ANSWERED, flags.contains(Flag.ANSWERED))
                 .setBool(DELETED, flags.contains(Flag.DELETED))
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
index 5261cc2..838d680 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
@@ -122,7 +122,7 @@ class CassandraMessageIdMapperTest extends MessageIdMapperTest {
             .block();
 
         assertThat(statementRecorder.listExecutedStatements(
-            StatementRecorder.Selector.preparedStatementStartingWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted," +
+            StatementRecorder.Selector.preparedStatementStartingWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted," +
                 "flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM imapUidTable")))
             .hasSize(1);
     }
@@ -206,7 +206,7 @@ class CassandraMessageIdMapperTest extends MessageIdMapperTest {
             cassandra.getConf()
                 .registerScenario(fail()
                     .forever()
-                    .whenQueryStartsWith("INSERT INTO imapUidTable (messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
+                    .whenQueryStartsWith("INSERT INTO imapUidTable (messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
 
             try {
                 message1.setUid(mapperProvider.generateMessageUid());
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
index 2734fd7..b131393 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
@@ -103,7 +103,7 @@ class CassandraMessageMapperTest extends MessageMapperTest {
             messageMapper.deleteMessages(benwaInboxMailbox, ImmutableList.of(message1.getUid(), message2.getUid(), message3.getUid()));
 
             assertThat(statementRecorder.listExecutedStatements(Selector.preparedStatementStartingWith(
-                "SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen," +
+                "SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen," +
                     "flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND ")))
                 .hasSize(1);
         }
@@ -292,7 +292,7 @@ class CassandraMessageMapperTest extends MessageMapperTest {
             cassandra.getConf()
                 .registerScenario(fail()
                     .forever()
-                    .whenQueryStartsWith("INSERT INTO imapUidTable (messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
+                    .whenQueryStartsWith("INSERT INTO imapUidTable (messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
 
             try {
                 messageMapper.add(benwaInboxMailbox, message1);
@@ -315,7 +315,7 @@ class CassandraMessageMapperTest extends MessageMapperTest {
             cassandra.getConf()
                 .registerScenario(fail()
                     .forever()
-                    .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
+                    .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,threadId,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
 
             try {
                 messageMapper.add(benwaInboxMailbox, message1);
@@ -343,7 +343,7 @@ class CassandraMessageMapperTest extends MessageMapperTest {
             cassandra.getConf()
                 .registerScenario(fail()
                     .times(5)
-                    .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
+                    .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,threadId,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
 
             messageMapper.add(benwaInboxMailbox, message1);
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java
index 57ad287..d7c7c46 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesServiceTest.java
@@ -172,7 +172,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 .registerScenario(awaitOn(barrier)
                     .thenExecuteNormally()
                     .times(1)
-                    .whenQueryStartsWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid;"));
+                    .whenQueryStartsWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid;"));
 
             Context context = new Context();
             Mono<Task.Result> task = testee.fixMessageInconsistencies(context, RunningOptions.DEFAULT).subscribeOn(Schedulers.elastic()).cache();
@@ -201,7 +201,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 .registerScenario(awaitOn(barrier)
                     .thenExecuteNormally()
                     .times(1)
-                    .whenQueryStartsWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid;"));
+                    .whenQueryStartsWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid;"));
 
             Context context = new Context();
             Mono<Task.Result> task = testee.fixMessageInconsistencies(context, RunningOptions.DEFAULT).subscribeOn(Schedulers.elastic()).cache();
@@ -292,7 +292,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 cassandra.getConf()
                     .registerScenario(fail()
                         .forever()
-                        .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags) VALUES (:mailboxId,:uid,:modSeq,:messageId,:flagAnswered,:flagDeleted,:flagDraft,:flagFlagged,:flagRecent,:flagSeen,:flagUser,:userFlags)"));
+                        .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,threadId,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags) VALUES (:mailboxId,:uid,:threadId,:modSeq,:messageId,:flagAnswered,:flagDeleted,:flagDraft,:flagFlagged,:flagRecent,:flagSeen,:flagUser,:userFlags)"));
 
                 assertThat(testee.fixMessageInconsistencies(new Context(), RunningOptions.DEFAULT).block())
                     .isEqualTo(Task.Result.PARTIAL);
@@ -306,7 +306,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 cassandra.getConf()
                     .registerScenario(fail()
                         .times(1)
-                        .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags) VALUES (:mailboxId,:uid,:modSeq,:messageId,:flagAnswered,:flagDeleted,:flagDraft,:flagFlagged,:flagRecent,:flagSeen,:flagUser,:userFlags)"));
+                        .whenQueryStartsWith("INSERT INTO messageIdTable (mailboxId,uid,threadId,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags) VALUES (:mailboxId,:uid,:threadId,:modSeq,:messageId,:flagAnswered,:flagDeleted,:flagDraft,:flagFlagged,:flagRecent,:flagSeen,:flagUser,:userFlags)"));
 
                 assertThat(testee.fixMessageInconsistencies(new Context(), RunningOptions.DEFAULT).block())
                     .isEqualTo(Task.Result.PARTIAL);
@@ -341,7 +341,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 cassandra.getConf()
                     .registerScenario(fail()
                         .times(1)
-                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid;"));
+                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid;"));
 
                 testee.fixMessageInconsistencies(context, RunningOptions.DEFAULT).block();
 
@@ -361,7 +361,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 cassandra.getConf()
                     .registerScenario(fail()
                         .times(1)
-                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid"));
+                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid"));
 
                 testee.fixMessageInconsistencies(context, RunningOptions.DEFAULT).block();
 
@@ -394,7 +394,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 .registerScenario(awaitOn(barrier)
                     .thenExecuteNormally()
                     .times(1)
-                    .whenQueryStartsWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted," +
+                    .whenQueryStartsWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted," +
                         "flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable " +
                         "WHERE mailboxId=:mailboxId AND uid=:uid;"));
 
@@ -516,7 +516,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 cassandra.getConf()
                     .registerScenario(fail()
                         .times(1)
-                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid"));
+                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM messageIdTable WHERE mailboxId=:mailboxId AND uid=:uid"));
 
                 testee.fixMessageInconsistencies(context, RunningOptions.DEFAULT).block();
 
@@ -536,7 +536,7 @@ public class SolveMessageInconsistenciesServiceTest {
                 cassandra.getConf()
                     .registerScenario(fail()
                         .times(1)
-                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM imapUidTable WHERE messageid=:messageid AND mailboxid=:mailboxid"));
+                        .whenQueryStartsWith("SELECT messageId,mailboxId,uid,threadId,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags FROM imapUidTable WHERE messageid=:messageid AND mailboxid=:mailboxid"));
 
                 testee.fixMessageInconsistencies(context, RunningOptions.DEFAULT).block();
 

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org