You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rc...@apache.org on 2020/06/10 04:10:44 UTC

[james-project] 08/08: MAILBOX-399 Make SearchQuery immutable

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 ce7c0c3afe261c3d898d2a048ae0619baaa056b1
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Jun 1 18:05:24 2020 +0700

    MAILBOX-399 Make SearchQuery immutable
    
    We applied the builder pattern and enforce immutable collection use.
---
 .../apache/james/mailbox/model/SearchQuery.java    | 104 ++--
 .../apache/james/mailbox/MailboxManagerTest.java   |  32 +-
 .../model/MultimailboxesSearchQueryTest.java       |   2 +-
 .../james/mailbox/model/SearchQueryTest.java       |  15 -
 .../elasticsearch/query/QueryConverter.java        |   2 +-
 .../ElasticSearchIntegrationTest.java              |  14 +-
 ...asticSearchListeningMessageSearchIndexTest.java |  26 +-
 .../search/ElasticSearchSearcherTest.java          |   2 +-
 .../lucene/search/LuceneMessageSearchIndex.java    |   2 +-
 .../LuceneMailboxMessageSearchIndexTest.java       | 162 ++----
 .../james/vault/DeletedMessageVaultHookTest.java   |   3 +-
 .../james/mailbox/store/StoreMessageManager.java   |   3 +-
 .../mailbox/store/search/MessageSearches.java      |   2 +-
 .../store/search/SimpleMessageSearchIndex.java     |   2 +-
 .../store/AbstractCombinationManagerTest.java      |  18 +-
 .../search/AbstractMessageSearchIndexTest.java     | 293 +++++------
 .../imap/processor/AbstractMailboxProcessor.java   |   4 +-
 .../james/imap/processor/SearchProcessor.java      |  13 +-
 .../imap/processor/base/SelectedMailboxImpl.java   |   2 +-
 .../james/imap/processor/SearchProcessorTest.java  |   3 +-
 .../jmap/draft/methods/GetMessageListMethod.java   |  14 +-
 .../james/jmap/draft/methods/ReferenceUpdater.java |   2 +-
 ...terToSearchQuery.java => FilterToCriteria.java} |  62 ++-
 .../mailet/ExtractMDNOriginalJMAPMessageId.java    |   2 +-
 .../jmap/draft/utils/FilterToCriteriaTest.java     | 433 ++++++++++++++++
 .../jmap/draft/utils/FilterToSearchQueryTest.java  | 556 ---------------------
 .../routes/DeletedMessagesVaultRoutesTest.java     |   2 +-
 27 files changed, 810 insertions(+), 965 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java
index 51fcb9a..d761753 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java
@@ -22,10 +22,9 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
-import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 
 import javax.mail.Flags;
@@ -36,6 +35,8 @@ import org.apache.james.mailbox.MessageUid;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * <p>
@@ -759,40 +760,78 @@ public class SearchQuery implements Serializable {
         return new MimeMessageIDCriterion(messageId);
     }
 
-    private final Set<MessageUid> recentMessageUids = new HashSet<>();
+    public static class Builder {
+        private final ImmutableList.Builder<Criterion> criterias;
+        private final ImmutableSet.Builder<MessageUid> recentMessageUids;
+        private Optional<ImmutableList<Sort>> sorts;
 
-    private final List<Criterion> criterias;
+        public Builder() {
+            criterias = ImmutableList.builder();
+            sorts = Optional.empty();
+            recentMessageUids = ImmutableSet.builder();
+        }
+
+        public Builder andCriteria(Criterion... criteria) {
+            return andCriteria(Arrays.asList(criteria));
+        }
+
+        public Builder andCriteria(Collection<Criterion> criteria) {
+            this.criterias.addAll(criteria);
+            return this;
+        }
+
+        public Builder sorts(Sort... sorts) {
+            return this.sorts(Arrays.asList(sorts));
+        }
+
+        public Builder sorts(List<Sort> sorts) {
+            if (sorts == null || sorts.isEmpty()) {
+                throw new IllegalArgumentException("There must be at least one Sort");
+            }
+            this.sorts = Optional.of(ImmutableList.copyOf(sorts));
+            return this;
+        }
 
-    private List<Sort> sorts = Collections.singletonList(new Sort(Sort.SortClause.Uid, Sort.Order.NATURAL));
+        public Builder addRecentMessageUids(Collection<MessageUid> uids) {
+            recentMessageUids.addAll(uids);
+            return this;
+        }
 
-    public SearchQuery(Criterion... criterias) {
-        this(new ArrayList<>(Arrays.asList(criterias)));
+        public SearchQuery build() {
+            return new SearchQuery(criterias.build(),
+                sorts.orElse(ImmutableList.of(new Sort(Sort.SortClause.Uid, Sort.Order.NATURAL))),
+                recentMessageUids.build());
+        }
     }
 
-    public SearchQuery() {
-        this(new ArrayList<>());
+    public static Builder builder() {
+        return new Builder();
     }
 
-    private SearchQuery(List<Criterion> criterias) {
-        this.criterias = criterias;
+    public static SearchQuery of(Criterion... criterias) {
+        return new Builder().andCriteria(criterias).build();
     }
 
-    public void andCriteria(Criterion crit) {
-        criterias.add(crit);
+    public static SearchQuery matchAll() {
+        return new Builder().build();
     }
 
-    public List<Criterion> getCriterias() {
-        return criterias;
+    public static SearchQuery allSortedWith(Sort... sorts) {
+        return new Builder().sorts(sorts).build();
     }
 
-    /**
-     * Set the {@link Sort}'s to use
-     */
-    public void setSorts(List<Sort> sorts) {
-        if (sorts == null || sorts.isEmpty()) {
-            throw new IllegalArgumentException("There must be at least one Sort");
-        }
+    private final ImmutableList<Criterion> criteria;
+    private final ImmutableList<Sort> sorts;
+    private final ImmutableSet<MessageUid> recentMessageUids;
+
+    private SearchQuery(ImmutableList<Criterion> criteria, ImmutableList<Sort> sorts, ImmutableSet<MessageUid> recentMessageUids) {
+        this.criteria = criteria;
         this.sorts = sorts;
+        this.recentMessageUids = recentMessageUids;
+    }
+
+    public List<Criterion> getCriteria() {
+        return criteria;
     }
 
     /**
@@ -800,8 +839,7 @@ public class SearchQuery implements Serializable {
      * They get "executed" in a chain, if the first does not give an result the
      * second will get executed etc.
      * 
-     * If not set via {@link #setSorts(List)} it will sort via
-     * {@link Sort.SortClause#Uid}
+     * Default to sort via {@link Sort.SortClause#Uid}
      * 
      * @return sorts
      */
@@ -820,24 +858,14 @@ public class SearchQuery implements Serializable {
         return recentMessageUids;
     }
 
-    /**
-     * Adds all the uids to the collection of recents.
-     * 
-     * @param uids
-     *            not null
-     */
-    public void addRecentMessageUids(Collection<MessageUid> uids) {
-        recentMessageUids.addAll(uids);
-    }
-
     @Override
     public String toString() {
-        return "Search:" + criterias.toString();
+        return "Search:" + criteria.toString();
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hashCode(criterias);
+        return Objects.hashCode(criteria, sorts, recentMessageUids);
     }
 
     @Override
@@ -845,7 +873,9 @@ public class SearchQuery implements Serializable {
         if (obj instanceof SearchQuery) {
             SearchQuery that = (SearchQuery) obj;
 
-            return Objects.equal(this.criterias, that.criterias);
+            return Objects.equal(this.criteria, that.criteria)
+                && Objects.equal(this.sorts, that.sorts)
+                && Objects.equal(this.recentMessageUids, that.recentMessageUids);
         }
         return false;
     }
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index c262c91..2eaa904 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -1205,7 +1205,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
                 .getId().getMessageId();
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .build();
 
 
@@ -1236,7 +1236,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
                 sessionFromDelegater);
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .build();
 
             assertThat(Flux.from(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
@@ -1264,7 +1264,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
                 sessionFromDelegater);
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .build();
 
             assertThat(Flux.from(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
@@ -1285,7 +1285,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             otherMailboxManager.appendMessage(AppendCommand.from(message), sessionFromDelegater);
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .build();
 
             assertThat(Flux.from(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
@@ -1306,7 +1306,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             otherMessageManager.appendMessage(AppendCommand.from(message), sessionFromDelegater);
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(otherMailboxId)
                 .build();
 
@@ -1327,7 +1327,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             otherMessageManager.appendMessage(AppendCommand.from(message), session);
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .notInMailboxes(otherMailboxId)
                 .build();
 
@@ -1348,7 +1348,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             otherMessageManager.appendMessage(AppendCommand.from(message), session);
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(otherMailboxId)
                 .notInMailboxes(otherMailboxId)
                 .build();
@@ -1379,7 +1379,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
                 .getId().getMessageId();
 
             MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(searchedMailboxId)
                 .build();
 
@@ -1852,12 +1852,12 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.moveMessages(MessageRange.all(), inbox, otherMailbox, session);
 
             MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(inboxId)
                 .build();
 
             MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(otherMailboxId)
                 .build();
 
@@ -1895,12 +1895,12 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.moveMessages(MessageRange.one(composedMessageId1.getUid()), inbox, otherMailbox, session);
 
             MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(inboxId)
                 .build();
 
             MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(otherMailboxId)
                 .build();
 
@@ -1989,12 +1989,12 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.copyMessages(MessageRange.all(), inbox, otherMailbox, session);
 
             MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(inboxId)
                 .build();
 
             MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(otherMailboxId)
                 .build();
 
@@ -2033,12 +2033,12 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.copyMessages(MessageRange.one(composedMessageId1.getUid()), inbox, otherMailbox, session);
 
             MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(inboxId)
                 .build();
 
             MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
-                .from(new SearchQuery())
+                .from(SearchQuery.matchAll())
                 .inMailboxes(otherMailboxId)
                 .build();
 
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MultimailboxesSearchQueryTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MultimailboxesSearchQueryTest.java
index 9f08817..6d50cf0 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MultimailboxesSearchQueryTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MultimailboxesSearchQueryTest.java
@@ -27,7 +27,7 @@ import com.google.common.collect.ImmutableSet;
 
 class MultimailboxesSearchQueryTest {
 
-    private static final SearchQuery EMPTY_QUERY = new SearchQuery();
+    private static final SearchQuery EMPTY_QUERY = SearchQuery.matchAll();
     private static final TestId.Factory FACTORY = new TestId.Factory();
     private static final MailboxId ID_1 = FACTORY.fromString("1");
     private static final MailboxId ID_2 = FACTORY.fromString("2");
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/SearchQueryTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/SearchQueryTest.java
index 2011617..487cd17 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/SearchQueryTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/SearchQueryTest.java
@@ -20,29 +20,14 @@
 
 package org.apache.james.mailbox.model;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 
 class SearchQueryTest {
-
     @Test
     void searchQueryShouldRespectBeanContract() {
         EqualsVerifier.forClass(SearchQuery.class)
-            .withOnlyTheseFields("criterias")
             .verify();
     }
-
-    @Test
-    void equalsShouldCompareCriteria() {
-        SearchQuery searchQuery1 = new SearchQuery();
-        SearchQuery searchQuery2 = new SearchQuery();
-        searchQuery1.andCriteria(SearchQuery.all());
-        searchQuery2.andCriteria(SearchQuery.all());
-
-        assertThat(searchQuery1).isEqualTo(searchQuery2);
-    }
-
 }
diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/QueryConverter.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/QueryConverter.java
index c61e670..9e3f9af 100644
--- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/QueryConverter.java
+++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/QueryConverter.java
@@ -56,7 +56,7 @@ public class QueryConverter {
     }
 
     private QueryBuilder generateQueryBuilder(SearchQuery searchQuery) {
-        List<SearchQuery.Criterion> criteria = searchQuery.getCriterias();
+        List<SearchQuery.Criterion> criteria = searchQuery.getCriteria();
         if (criteria.isEmpty()) {
             return criterionConverter.convertCriterion(SearchQuery.all());
         } else if (criteria.size() == 1) {
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
index 2e53000..279c1c6 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
@@ -135,7 +135,7 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        assertThat(messageManager.search(new SearchQuery(SearchQuery.address(SearchQuery.AddressType.To, recipient)), session))
+        assertThat(messageManager.search(SearchQuery.of(SearchQuery.address(SearchQuery.AddressType.To, recipient)), session))
             .containsExactly(composedMessageId.getUid());
     }
 
@@ -154,7 +154,7 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        assertThat(messageManager.search(new SearchQuery(SearchQuery.address(SearchQuery.AddressType.To, recipient)), session))
+        assertThat(messageManager.search(SearchQuery.of(SearchQuery.address(SearchQuery.AddressType.To, recipient)), session))
             .containsExactly(composedMessageId.getUid());
     }
 
@@ -173,7 +173,7 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        assertThat(messageManager.search(new SearchQuery(SearchQuery.bodyContains("0123456789")), session))
+        assertThat(messageManager.search(SearchQuery.of(SearchQuery.bodyContains("0123456789")), session))
             .containsExactly(composedMessageId.getUid());
     }
 
@@ -192,7 +192,7 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        assertThat(messageManager.search(new SearchQuery(SearchQuery.bodyContains("matchMe")), session))
+        assertThat(messageManager.search(SearchQuery.of(SearchQuery.bodyContains("matchMe")), session))
             .containsExactly(composedMessageId.getUid());
     }
 
@@ -212,7 +212,7 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        assertThat(messageManager.search(new SearchQuery(SearchQuery.bodyContains(reasonableLongTerm)), session))
+        assertThat(messageManager.search(SearchQuery.of(SearchQuery.bodyContains(reasonableLongTerm)), session))
             .containsExactly(composedMessageId.getUid());
     }
 
@@ -236,7 +236,7 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        assertThat(messageManager.search(new SearchQuery(SearchQuery.headerExists("Custom-header")), session))
+        assertThat(messageManager.search(SearchQuery.of(SearchQuery.headerExists("Custom-header")), session))
             .containsExactly(customDateHeaderMessageId.getUid(), customStringHeaderMessageId.getUid());
     }
 
@@ -260,7 +260,7 @@ class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        assertThat(messageManager.search(new SearchQuery(SearchQuery.all()), session))
+        assertThat(messageManager.search(SearchQuery.of(SearchQuery.all()), session))
             .contains(customStringHeaderMessageId.getUid());
     }
 }
\ No newline at end of file
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java
index e3f16a3..5b617bc 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndexTest.java
@@ -195,7 +195,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.add(session, mailbox, MESSAGE_1).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_1.getUid());
     }
@@ -206,7 +206,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.add(session, mailbox, MESSAGE_WITH_ATTACHMENT).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_WITH_ATTACHMENT.getUid());
     }
@@ -218,7 +218,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_1.getUid());
     }
@@ -230,7 +230,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
 
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_1.getUid(), MESSAGE_2.getUid());
     }
@@ -248,7 +248,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.add(session, mailbox, MESSAGE_WITH_ATTACHMENT).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_WITH_ATTACHMENT.getUid());
     }
@@ -272,7 +272,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.delete(session, mailbox, Lists.newArrayList(MESSAGE_UID_1)).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .isEmpty();
     }
@@ -287,7 +287,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.delete(session, mailbox, Lists.newArrayList(MESSAGE_UID_1)).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_2.getUid());
     }
@@ -302,7 +302,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.delete(session, mailbox, Lists.newArrayList(MESSAGE_UID_1, MESSAGE_UID_2)).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .isEmpty();
     }
@@ -316,7 +316,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.delete(session, mailbox, Lists.newArrayList(MESSAGE_UID_1)).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .isEmpty();
     }
@@ -354,7 +354,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.update(session, mailbox, Lists.newArrayList(updatedFlags)).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
+        SearchQuery query = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_1.getUid());
     }
@@ -375,7 +375,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.update(session, mailbox, Lists.newArrayList(updatedFlags)).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
+        SearchQuery query = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
         assertThat(testee.search(session, mailbox, query))
             .isEmpty();
     }
@@ -397,7 +397,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.update(session, mailbox, Lists.newArrayList(updatedFlags)).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
+        SearchQuery query = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
         assertThat(testee.search(session, mailbox, query))
             .containsExactly(MESSAGE_1.getUid());
     }
@@ -431,7 +431,7 @@ class ElasticSearchListeningMessageSearchIndexTest {
         testee.deleteAll(session, mailbox.getMailboxId()).block();
         elasticSearch.awaitForElasticSearch();
 
-        SearchQuery query = new SearchQuery(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         assertThat(testee.search(session, mailbox, query))
             .isEmpty();
     }
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcherTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcherTest.java
index 686af32..956661a 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcherTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcherTest.java
@@ -147,7 +147,7 @@ class ElasticSearchSearcherTest {
         elasticSearch.awaitForElasticSearch();
 
         MultimailboxesSearchQuery multimailboxesSearchQuery = MultimailboxesSearchQuery
-            .from(new SearchQuery(SearchQuery.all()))
+            .from(SearchQuery.of(SearchQuery.all()))
             .inMailboxes(mailboxIds)
             .build();
         List<MessageId> expectedMessageIds = composedMessageIds
diff --git a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
index e3a4f25..d3da37c 100644
--- a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
+++ b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
@@ -490,7 +490,7 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex {
             // Not return flags documents
             query.add(new PrefixQuery(new Term(FLAGS_FIELD, "")), BooleanClause.Occur.MUST_NOT);
 
-            List<Criterion> crits = searchQuery.getCriterias();
+            List<Criterion> crits = searchQuery.getCriteria();
             for (Criterion crit : crits) {
                 query.add(createQuery(crit, inMailboxes, searchQuery.getRecentMessageUids()), BooleanClause.Occur.MUST);
             }
diff --git a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
index d40f8e3..be30a35 100644
--- a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
+++ b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
@@ -188,128 +188,112 @@ class LuceneMailboxMessageSearchIndexTest {
 
     @Test
     void bodySearchShouldMatchPhraseInBody() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains(CUSTARD));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains(CUSTARD));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
 
     @Test
     void bodySearchShouldNotMatchAbsentPhraseInBody() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains(CUSTARD + CUSTARD));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains(CUSTARD + CUSTARD));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).isEmpty();
     }
     
     @Test
     void bodySearchShouldBeCaseInsensitive() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains(RHUBARD));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains(RHUBARD));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
 
     @Test
     void bodySearchNotMatchPhraseOnlyInFrom() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains(FROM_ADDRESS));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains(FROM_ADDRESS));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).isEmpty();
     }
 
     @Test
     void bodySearchShouldNotMatchPhraseOnlyInSubject() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains(SUBJECT_PART));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains(SUBJECT_PART));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).isEmpty();
     }
 
     @Test
     void textSearchShouldMatchPhraseInBody() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.mailContains(CUSTARD));
+        SearchQuery query = SearchQuery.of(SearchQuery.mailContains(CUSTARD));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
 
     @Test
     void textSearchShouldNotAbsentMatchPhraseInBody() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.mailContains(CUSTARD + CUSTARD));
+        SearchQuery query = SearchQuery.of(SearchQuery.mailContains(CUSTARD + CUSTARD));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).isEmpty();
     }
 
     @Test
     void textSearchMatchShouldBeCaseInsensitive() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.mailContains(RHUBARD.toLowerCase(Locale.US)));
+        SearchQuery query = SearchQuery.of(SearchQuery.mailContains(RHUBARD.toLowerCase(Locale.US)));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
 
     @Test
     void addressSearchShouldMatchToFullAddress() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.address(AddressType.To,FROM_ADDRESS));
+        SearchQuery query = SearchQuery.of(SearchQuery.address(AddressType.To,FROM_ADDRESS));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
 
     @Test
     void addressSearchShouldMatchToDisplayName() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.address(AddressType.To,"Harry"));
+        SearchQuery query = SearchQuery.of(SearchQuery.address(AddressType.To,"Harry"));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
     
     @Test
     void addressSearchShouldMatchToEmail() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.address(AddressType.To,"Harry@example.org"));
+        SearchQuery query = SearchQuery.of(SearchQuery.address(AddressType.To,"Harry@example.org"));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
     
     @Test
     void addressSearchShouldMatchFrom() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.address(AddressType.From,"ser-from@domain.or"));
+        SearchQuery query = SearchQuery.of(SearchQuery.address(AddressType.From,"ser-from@domain.or"));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
 
     @Test
     void textSearchShouldMatchPhraseOnlyInToHeader() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.mailContains(FROM_ADDRESS));
+        SearchQuery query = SearchQuery.of(SearchQuery.mailContains(FROM_ADDRESS));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
     
     @Test
     void textSearchShouldMatchPhraseOnlyInSubjectHeader() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.mailContains(SUBJECT_PART));
+        SearchQuery query = SearchQuery.of(SearchQuery.mailContains(SUBJECT_PART));
         Stream<MessageUid> result = index.search(session, mailbox3, query);
         assertThat(result).containsExactly(uid5);
     }
     
     @Test
     void searchAllShouldMatchAllMailboxEmails() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         Stream<MessageUid> result = index.search(session, mailbox2, query);
         assertThat(result).containsExactly(uid2);
     }
 
     @Test
     void searchBodyInAllMailboxesShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains("My Body"));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains("My Body"));
 
         List<MessageId> result = index.search(session, ImmutableList.of(mailbox.getMailboxId(), mailbox2.getMailboxId(), mailbox3.getMailboxId()), query, LIMIT)
             .collectList().block();
@@ -319,8 +303,7 @@ class LuceneMailboxMessageSearchIndexTest {
 
     @Test
     void searchBodyInSpecificMailboxesShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains("My Body"));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains("My Body"));
 
         List<MessageId> result = index.search(session,
                 ImmutableList.of(mailbox.getMailboxId(), mailbox3.getMailboxId()),
@@ -333,8 +316,7 @@ class LuceneMailboxMessageSearchIndexTest {
 
     @Test
     void searchAllShouldMatchAllUserEmails() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
 
         List<MessageId> result = index.search(session, ImmutableList.of(mailbox.getMailboxId(), mailbox2.getMailboxId(), mailbox3.getMailboxId()), query, LIMIT)
             .collectList().block();
@@ -345,8 +327,7 @@ class LuceneMailboxMessageSearchIndexTest {
 
     @Test
     void searchAllShouldLimitTheSize() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
 
         int limit = 1;
         List<MessageId> result = index.search(session, ImmutableList.of(mailbox.getMailboxId(), mailbox2.getMailboxId(), mailbox3.getMailboxId()), query, limit)
@@ -357,58 +338,51 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void flagSearchShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.flagIsSet(Flag.DELETED));
+        SearchQuery query = SearchQuery.of(SearchQuery.flagIsSet(Flag.DELETED));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4);
     }
     
     @Test
     void bodySearchShouldMatchSeveralEmails() throws Exception {    
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.bodyContains("body"));
+        SearchQuery query = SearchQuery.of(SearchQuery.bodyContains("body"));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
     }
     
     @Test
     void textSearchShouldMatchSeveralEmails() throws Exception {    
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.mailContains("body"));
+        SearchQuery query = SearchQuery.of(SearchQuery.mailContains("body"));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
     }
     
     @Test
     void headerSearchShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.headerContains("Subject", "test"));
+        SearchQuery query = SearchQuery.of(SearchQuery.headerContains("Subject", "test"));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid4);
     }
     
     @Test
     void headerExistsShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.headerExists("Subject"));
+        SearchQuery query = SearchQuery.of(SearchQuery.headerExists("Subject"));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid4);
     }
     
     @Test
     void flagUnsetShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.flagIsUnSet(Flag.DRAFT));
+        SearchQuery query = SearchQuery.of(SearchQuery.flagIsUnSet(Flag.DRAFT));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
     }
     
     @Test
     void internalDateBeforeShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
         Calendar cal = Calendar.getInstance();
         cal.setTime(new Date());
-        query.andCriteria(SearchQuery.internalDateBefore(cal.getTime(), DateResolution.Day));
+        SearchQuery query = SearchQuery.of(SearchQuery.internalDateBefore(cal.getTime(), DateResolution.Day));
         
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3);
@@ -417,10 +391,9 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void internalDateAfterShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
         Calendar cal = Calendar.getInstance();
         cal.setTime(new Date());
-        query.andCriteria(SearchQuery.internalDateAfter(cal.getTime(), DateResolution.Day));
+        SearchQuery query = SearchQuery.of(SearchQuery.internalDateAfter(cal.getTime(), DateResolution.Day));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid4);
     }
@@ -429,70 +402,62 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void internalDateOnShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
         Calendar cal = Calendar.getInstance();
         cal.setTime(new Date());
-        query.andCriteria(SearchQuery.internalDateOn(cal.getTime(), DateResolution.Day));
+        SearchQuery query = SearchQuery.of(SearchQuery.internalDateOn(cal.getTime(), DateResolution.Day));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1);
     }
     
     @Test
     void uidSearchShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
         Calendar cal = Calendar.getInstance();
         cal.setTime(new Date());
-        query.andCriteria(SearchQuery.uid(new SearchQuery.UidRange[] {new SearchQuery.UidRange(uid1)}));
+        SearchQuery query = SearchQuery.of(SearchQuery.uid(new SearchQuery.UidRange[] {new SearchQuery.UidRange(uid1)}));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1);
     }
     
     @Test
     void uidRangeSearchShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
         Calendar cal = Calendar.getInstance();
         cal.setTime(new Date());
-        query.andCriteria(SearchQuery.uid(new SearchQuery.UidRange[] {new SearchQuery.UidRange(uid1), new SearchQuery.UidRange(uid3,uid4)}));
+        SearchQuery query = SearchQuery.of(SearchQuery.uid(new SearchQuery.UidRange[] {new SearchQuery.UidRange(uid1), new SearchQuery.UidRange(uid3,uid4)}));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
     }
     
     @Test
     void sizeEqualsShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.sizeEquals(200));
+        SearchQuery query = SearchQuery.of(SearchQuery.sizeEquals(200));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1);
     }
     
     @Test
     void sizeLessThanShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.sizeLessThan(200));
+        SearchQuery query = SearchQuery.of(SearchQuery.sizeLessThan(200));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4);
     }
     
     @Test
     void sizeGreaterThanShouldMatch() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.sizeGreaterThan(6));
+        SearchQuery query = SearchQuery.of(SearchQuery.sizeGreaterThan(6));
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
     }
     
     @Test
     void uidShouldBeSorted() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
     }
     
     @Test
     void uidReverseSortShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.Uid, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.Uid, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid4, uid3, uid1);
@@ -500,8 +465,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnSentDateShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.SentDate, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.SentDate, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4, uid1);
@@ -509,8 +473,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnSentDateShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.SentDate, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.SentDate, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid4, uid3);
@@ -518,8 +481,7 @@ class LuceneMailboxMessageSearchIndexTest {
 
     @Test
     void sortOnSubjectShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.BaseSubject, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.BaseSubject, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid1, uid4);
@@ -527,8 +489,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnSubjectShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.BaseSubject, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.BaseSubject, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid4, uid1, uid3);
@@ -536,8 +497,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnMailboxFromShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.MailboxFrom, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.MailboxFrom, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4, uid1);
@@ -545,8 +505,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnMailboxFromShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.MailboxFrom, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.MailboxFrom, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid4, uid3);
@@ -554,8 +513,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnMailboxCCShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.MailboxCc, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.MailboxCc, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
@@ -563,8 +521,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnMailboxCCShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.MailboxCc, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.MailboxCc, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4, uid1);
@@ -572,8 +529,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnMailboxToShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.MailboxTo, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.MailboxTo, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid4, uid1, uid3);
@@ -581,8 +537,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnMailboxToShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.MailboxTo, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.MailboxTo, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid1, uid4);
@@ -590,8 +545,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnDisplayToShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.DisplayTo, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.DisplayTo, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid4, uid1, uid3);
@@ -599,8 +553,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnDisplayToShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.DisplayTo, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.DisplayTo, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid1, uid4);
@@ -608,8 +561,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnDisplayFromShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.DisplayFrom, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.DisplayFrom, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4, uid1);
@@ -617,8 +569,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnDisplayFromShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.DisplayFrom, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.DisplayFrom, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid4, uid3);
@@ -626,8 +577,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnArrivalDateShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.Arrival, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid1, uid4);
@@ -635,8 +585,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnArrivalDateShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.Arrival, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid4, uid1, uid3);
@@ -644,8 +593,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void sortOnSizeShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.Size, Order.NATURAL)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.Size, Order.NATURAL));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4, uid1);
@@ -653,8 +601,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void reverseSortOnSizeShouldReturnWellOrderedResults() throws Exception {
-        SearchQuery query = new SearchQuery(SearchQuery.all());
-        query.setSorts(ImmutableList.of(new Sort(SortClause.Size, Order.REVERSE)));
+        SearchQuery query = SearchQuery.allSortedWith(new Sort(SortClause.Size, Order.REVERSE));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid1, uid3, uid4);
@@ -662,8 +609,7 @@ class LuceneMailboxMessageSearchIndexTest {
     
     @Test
     void notOperatorShouldReverseMatching() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.not(SearchQuery.uid(new SearchQuery.UidRange[] { new SearchQuery.UidRange(uid1)})));
+        SearchQuery query = SearchQuery.of(SearchQuery.not(SearchQuery.uid(new SearchQuery.UidRange[] { new SearchQuery.UidRange(uid1)})));
 
         Stream<MessageUid> result = index.search(session, mailbox, query);
         assertThat(result).containsExactly(uid3, uid4);
diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
index 53b9fc9..3b6fd29 100644
--- a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
+++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
@@ -137,8 +137,7 @@ class DeletedMessageVaultHookTest {
             .setDate(INTERNAL_DATE)
             .build();
 
-        searchQuery = new SearchQuery();
-        searchQuery.andCriteria(SearchQuery.internalDateOn(INTERNAL_DATE, SearchQuery.DateResolution.Second));
+        searchQuery = SearchQuery.of(SearchQuery.internalDateOn(INTERNAL_DATE, SearchQuery.DateResolution.Second));
 
         aliceSession = mailboxManager.createSystemSession(ALICE);
         bobSession = mailboxManager.createSystemSession(BOB);
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
index c2d76d8..d2f6520 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
@@ -123,6 +123,7 @@ public class StoreMessageManager implements MessageManager {
      * later!</strong>
      */
     protected static final Flags MINIMAL_PERMANET_FLAGS;
+    private static final SearchQuery LIST_ALL_QUERY = SearchQuery.of(SearchQuery.all());
 
     private static class MediaType {
         final String mediaType;
@@ -694,7 +695,7 @@ public class StoreMessageManager implements MessageManager {
 
     @Override
     public Stream<MessageUid> search(SearchQuery query, MailboxSession mailboxSession) throws MailboxException {
-        if (query.equals(new SearchQuery(SearchQuery.all()))) {
+        if (query.equals(LIST_ALL_QUERY)) {
             return listAllMessageUids(mailboxSession);
         }
         return index.search(mailboxSession, getMailboxEntity(), query);
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java
index 583ec25..97692bf 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java
@@ -135,7 +135,7 @@ public class MessageSearches implements Iterable<SimpleMessageSearchIndex.Search
      *         <code>false</code> otherwise
      */
     private boolean isMatch(MailboxMessage message) throws MailboxException {
-        final List<SearchQuery.Criterion> criteria = query.getCriterias();
+        final List<SearchQuery.Criterion> criteria = query.getCriteria();
         final Collection<MessageUid> recentMessageUids = query.getRecentMessageUids();
         if (criteria != null) {
             for (SearchQuery.Criterion criterion : criteria) {
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java
index 3560b96..f3d52bb 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java
@@ -124,7 +124,7 @@ public class SimpleMessageSearchIndex implements MessageSearchIndex {
 
         final SortedSet<MailboxMessage> hitSet = new TreeSet<>();
 
-        UidCriterion uidCrit = findConjugatedUidCriterion(query.getCriterias());
+        UidCriterion uidCrit = findConjugatedUidCriterion(query.getCriteria());
         if (uidCrit != null) {
             // if there is a conjugated uid range criterion in the query tree we can optimize by
             // only fetching this uid range
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractCombinationManagerTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractCombinationManagerTest.java
index 97dcf42..f0a8f81 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractCombinationManagerTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractCombinationManagerTest.java
@@ -107,8 +107,7 @@ public abstract class AbstractCombinationManagerTest {
 
     @Test
     void searchFromMessageManagerShouldReturnMessagesUsingSetInMailboxesFromMessageIdManager() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
 
         MessageId messageId = messageManager1.appendMessage(MessageManager.AppendCommand.from(mailContent), session)
             .getId().getMessageId();
@@ -120,8 +119,7 @@ public abstract class AbstractCombinationManagerTest {
 
     @Test
     void searchFromMessageManagerShouldReturnMessagesUsingSetInMailboxesFromMessageIdManagerWhenSearchByMailboxQueryWithMailboxPath() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
 
         MessageId messageId = messageManager1.appendMessage(MessageManager.AppendCommand.from(mailContent), session)
             .getId().getMessageId();
@@ -139,8 +137,7 @@ public abstract class AbstractCombinationManagerTest {
 
     @Test
     void searchFromMessageManagerShouldReturnMessagesUsingSetInMailboxesFromMessageIdManagerWhenSearchByMailboxQueryWithUsername() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
 
         ComposedMessageId composedMessageId = messageManager1.appendMessage(MessageManager.AppendCommand.from(mailContent), session).getId();
 
@@ -153,8 +150,7 @@ public abstract class AbstractCombinationManagerTest {
 
     @Test
     void searchFromMailboxManagerShouldReturnMessagesUsingSetInMailboxesFromMessageIdManagerWhenSearchByMultiMailboxes() throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
+        SearchQuery query = SearchQuery.of(SearchQuery.all());
 
         MultimailboxesSearchQuery.Builder builder = MultimailboxesSearchQuery.from(query);
         builder.inMailboxes(mailbox1.getMailboxId(), mailbox2.getMailboxId());
@@ -511,7 +507,7 @@ public abstract class AbstractCombinationManagerTest {
             .get()
             .getUid();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.all());
         assertThat(messageManager2.search(searchQuery, session))
             .hasSize(1)
             .containsOnly(uid2);
@@ -525,7 +521,7 @@ public abstract class AbstractCombinationManagerTest {
 
         messageIdManager.delete(messageId, ImmutableList.of(mailbox1.getMailboxId()), session);
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.all());
         assertThat(messageManager1.search(searchQuery, session)).isEmpty();
     }
 
@@ -540,7 +536,7 @@ public abstract class AbstractCombinationManagerTest {
 
         messageIdManager.delete(ImmutableList.of(messageId1, messageId2), session);
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.all());
         assertThat(messageManager1.search(searchQuery, session)).isEmpty();
     }
 
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
index 7c55990..4f3e1c2 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
@@ -243,7 +243,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
 
         List<MessageId> result = messageSearchIndex.search(session,
             ImmutableList.of(mailbox.getMailboxId(), mailbox2.getMailboxId()),
@@ -276,7 +276,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
 
         List<MessageId> result = messageSearchIndex.search(session,
             ImmutableList.of(mailbox.getMailboxId(), mailbox2.getMailboxId()),
@@ -312,7 +312,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
 
         int limit = 10;
         List<MessageId> result = messageSearchIndex.search(session,
@@ -327,7 +327,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void whenEmptyListOfMailboxGivenSearchShouldReturnEmpty() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
 
         List<MessageId> result = messageSearchIndex.search(session,
             ImmutableList.of(),
@@ -344,7 +344,7 @@ public abstract class AbstractMessageSearchIndexTest {
         assumeTrue(messageIdManager != null);
         messageIdManager.setInMailboxes(m1.getMessageId(), ImmutableList.of(mailbox.getMailboxId(), mailbox2.getMailboxId()), session);
 
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
 
         myFolderMessageManager.appendMessage(MessageManager.AppendCommand.builder()
             .withFlags(new Flags(Flags.Flag.SEEN))
@@ -366,7 +366,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void searchShouldThrowWhenSessionIsNull() {
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
         MailboxSession session = null;
         
         assertThatThrownBy(() -> messageSearchIndex.search(session, mailbox, searchQuery))
@@ -375,7 +375,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void emptySearchQueryShouldReturnAllUids() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
         
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -383,7 +383,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void allShouldReturnAllUids() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.all());
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -392,7 +392,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void bodyContainsShouldReturnUidOfMessageContainingTheGivenText() throws MailboxException {
         /* Only mail4.eml contains word MAILET-94 */
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.bodyContains("MAILET-94"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.bodyContains("MAILET-94"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
@@ -402,7 +402,7 @@ public abstract class AbstractMessageSearchIndexTest {
     protected void bodyContainsShouldReturnUidOfMessageContainingTheApproximativeText() throws MailboxException {
         /* mail1.eml contains words created AND summary
            mail.eml contains created and thus matches the query with a low score */
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.bodyContains("created summary"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.bodyContains("created summary"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m2.getUid(), m8.getUid());
@@ -410,7 +410,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void hasAttachmentShouldOnlyReturnMessageThatHasAttachmentWhichAreNotInline() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.hasAttachment());
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.hasAttachment());
 
         assertThat(messageSearchIndex.search(session, mailbox2, searchQuery))
             .containsOnly(mailWithAttachment.getUid());
@@ -425,7 +425,7 @@ public abstract class AbstractMessageSearchIndexTest {
             session).getId();
         await();
         
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.all());
 
         assertThat(messageSearchIndex.search(session, mailbox2, searchQuery))
             .contains(mailWithDotsInHeader.getUid());
@@ -440,7 +440,7 @@ public abstract class AbstractMessageSearchIndexTest {
             session).getId();
         await();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.headerExists("X-header.with.dots"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.headerExists("X-header.with.dots"));
 
         assertThat(messageSearchIndex.search(session, mailbox2, searchQuery))
             .contains(mailWithDotsInHeader.getUid());
@@ -459,7 +459,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.or(ImmutableList.of(
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.or(ImmutableList.of(
             SearchQuery.address(AddressType.From, emailToSearch),
             SearchQuery.address(AddressType.To, emailToSearch),
             SearchQuery.address(AddressType.Cc, emailToSearch),
@@ -474,7 +474,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void hasNoAttachmenShouldOnlyReturnMessageThatHasNoAttachmentWhichAreNotInline() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.hasNoAttachment());
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.hasNoAttachment());
 
         assertThat(messageSearchIndex.search(session, mailbox2, searchQuery))
             .containsOnly(mOther.getUid(), mailWithInlinedAttachment.getUid());
@@ -482,7 +482,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsSetShouldReturnUidOfMessageMarkedAsDeletedWhenUsedWithFlagDeleted() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.DELETED));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.DELETED));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid());
@@ -490,7 +490,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsSetShouldReturnUidOfMessageMarkedAsAnsweredWhenUsedWithFlagAnswered() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m2.getUid());
@@ -498,7 +498,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsSetShouldReturnUidOfMessageMarkedAsDraftWhenUsedWithFlagDraft() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.DRAFT));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.DRAFT));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m3.getUid());
@@ -507,7 +507,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void flagIsSetShouldReturnUidOfMessageMarkedAsRecentWhenUsedWithFlagRecent() throws MailboxException {
         // Only message 7 is not marked as RECENT
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.RECENT));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.RECENT));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m8.getUid(), m9.getUid());
@@ -515,7 +515,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsSetShouldReturnUidOfMessageMarkedAsFlaggedWhenUsedWithFlagFlagged() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.FLAGGED));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.FLAGGED));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
@@ -524,7 +524,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void flagIsSetShouldReturnUidOfMessageMarkedAsSeenWhenUsedWithFlagSeen() throws MailboxException {
         // Only message 6 is marked as read.
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.SEEN));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.SEEN));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m6.getUid());
@@ -540,7 +540,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.SEEN));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.SEEN));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .contains(m5.getUid());
@@ -548,7 +548,7 @@ public abstract class AbstractMessageSearchIndexTest {
     
     @Test
     protected void multimailboxSearchShouldReturnUidOfMessageMarkedAsSeenInAllMailboxes() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.SEEN));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.SEEN));
 
         List<MessageId> actual = messageSearchIndex.search(
             session,
@@ -562,7 +562,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void multimailboxSearchShouldReturnUidOfMessageMarkedAsSeenInOneMailbox() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.SEEN));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.SEEN));
 
         List<MessageId> actual = messageSearchIndex.search(session, ImmutableList.of(mailbox.getMailboxId()), searchQuery, LIMIT)
             .collectList().block();
@@ -572,7 +572,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void multimailboxSearchShouldReturnUidOfMessageWithExpectedFromInTwoMailboxes() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.From, "murari"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.From, "murari"));
 
         List<MessageId> actual = messageSearchIndex.search(
             session,
@@ -586,7 +586,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void multimailboxSearchShouldReturnUidOfMessageMarkedAsSeenInTwoMailboxes() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.SEEN));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.SEEN));
 
         List<MessageId> actual = messageSearchIndex.search(
             session,
@@ -600,7 +600,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void multimailboxSearchShouldLimitTheSize() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet(Flags.Flag.SEEN));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet(Flags.Flag.SEEN));
 
         long limit = 1;
         List<MessageId> actual = messageSearchIndex.search(
@@ -617,7 +617,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void multimailboxSearchShouldWorkWithOtherUserMailbox() throws  MailboxException {
         assumeTrue(storeMailboxManager.hasCapability(MailboxManager.MailboxCapabilities.ACL));
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
 
         long limit = 256;
         List<MessageId> actual = messageSearchIndex.search(
@@ -633,7 +633,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsSetShouldReturnUidsOfMessageContainingAGivenUserFlag() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet("Hello"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet("Hello"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m8.getUid());
@@ -641,7 +641,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void userFlagsShouldBeMatchedExactly() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsSet("Hello bonjour"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsSet("Hello bonjour"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .isEmpty();
@@ -649,7 +649,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsDeletedWhenUsedWithFlagDeleted() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsUnSet(Flags.Flag.DELETED));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsUnSet(Flags.Flag.DELETED));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -657,7 +657,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsAnsweredWhenUsedWithFlagAnswered() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsUnSet(Flags.Flag.ANSWERED));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsUnSet(Flags.Flag.ANSWERED));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -665,7 +665,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsDraftWhenUsedWithFlagDraft() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsUnSet(Flags.Flag.DRAFT));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsUnSet(Flags.Flag.DRAFT));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -674,7 +674,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsRecentWhenUsedWithFlagRecent() throws MailboxException {
         // Only message 7 is not marked as RECENT
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsUnSet(Flags.Flag.RECENT));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsUnSet(Flags.Flag.RECENT));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m7.getUid());
@@ -682,7 +682,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsFlaggedWhenUsedWithFlagFlagged() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsUnSet(Flags.Flag.FLAGGED));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsUnSet(Flags.Flag.FLAGGED));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -691,7 +691,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsSeenWhenUsedWithFlagSeen() throws MailboxException {
         // Only message 6 is marked as read.
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsUnSet(Flags.Flag.SEEN));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsUnSet(Flags.Flag.SEEN));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -699,7 +699,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void flagIsUnSetShouldReturnUidsOfMessageNotContainingAGivenUserFlag() throws MailboxException {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.flagIsUnSet("Hello"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.flagIsUnSet("Hello"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m7.getUid(),  m9.getUid());
@@ -707,7 +707,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void internalDateAfterShouldReturnMessagesAfterAGivenDate() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.internalDateAfter(
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.internalDateAfter(
             new Date(1404252000000L),
             DateResolution.Day));
         // Date : 2014/07/02 00:00:00.000 ( Paris time zone )
@@ -718,7 +718,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void internalDateBeforeShouldReturnMessagesBeforeAGivenDate() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.internalDateBefore(
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.internalDateBefore(
             new Date(1391295600000L),
             DateResolution.Day));
         // Date : 2014/02/02 00:00:00.000 ( Paris time zone )
@@ -729,7 +729,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void internalDateOnShouldReturnMessagesOfTheGivenDate() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.internalDateOn(
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.internalDateOn(
             new Date(1393714800000L),
             DateResolution.Day));
         // Date : 2014/03/02 00:00:00.000 ( Paris time zone )
@@ -740,11 +740,11 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void sentDateAfterShouldReturnMessagesAfterAGivenDate() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.sentDateAfter(
-            new Date(1433408400000L),
-            DateResolution.Second));
         // Date : 2015/06/04 11:00:00.000 ( Paris time zone )
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.sentDateAfter(new Date(1433408400000L), DateResolution.Second))
+            .sorts(new Sort(SortClause.Arrival, Order.REVERSE))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m3.getUid(), m2.getUid());
@@ -752,11 +752,11 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void sentDateBeforeShouldReturnMessagesBeforeAGivenDate() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.sentDateBefore(
-            new Date(1433109600000L),
-            DateResolution.Day));
         // Date : 2015/06/01 00:00:00.000 ( Paris time zone )
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.sentDateBefore(new Date(1433109600000L), DateResolution.Day))
+            .sorts(new Sort(SortClause.Arrival, Order.REVERSE))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
@@ -764,11 +764,11 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void sentDateOnShouldReturnMessagesOfTheGivenDate() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.sentDateOn(
-            new Date(1433224800000L),
-            DateResolution.Day));
         // Date : 2015/06/02 08:00:00.000 ( Paris time zone )
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.sentDateOn(new Date(1433224800000L), DateResolution.Day))
+            .sorts(new Sort(SortClause.Arrival, Order.REVERSE))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m4.getUid(), m9.getUid());
@@ -776,7 +776,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void modSeqEqualsShouldReturnUidsOfMessageHavingAGivenModSeq() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.modSeqEquals(2L));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.modSeqEquals(2L));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m2.getUid());
@@ -784,7 +784,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void modSeqGreaterThanShouldReturnUidsOfMessageHavingAGreaterModSeq() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.modSeqGreaterThan(7L));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.modSeqGreaterThan(7L));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m7.getUid(), m8.getUid(), m9.getUid());
@@ -792,7 +792,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void modSeqLessThanShouldReturnUidsOfMessageHavingAGreaterModSeq() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.modSeqLessThan(3L));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.modSeqLessThan(3L));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid());
@@ -801,7 +801,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void sizeGreaterThanShouldReturnUidsOfMessageExceedingTheSpecifiedSize() throws Exception {
         // Only message 6 is over 6.8 KB
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.sizeGreaterThan(6800L));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.sizeGreaterThan(6800L));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m6.getUid());
@@ -810,7 +810,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void sizeLessThanShouldReturnUidsOfMessageNotExceedingTheSpecifiedSize() throws Exception {
         // Only message 2 3 4 5 7 9 are under 5 KB
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.sizeLessThan(5000L));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.sizeLessThan(5000L));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m7.getUid(), m9.getUid());
@@ -818,7 +818,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void headerContainsShouldReturnUidsOfMessageHavingThisHeaderWithTheSpecifiedValue() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.headerContains("Precedence", "list"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.headerContains("Precedence", "list"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m6.getUid(), m8.getUid(), m9.getUid());
@@ -826,7 +826,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void headerExistsShouldReturnUidsOfMessageHavingThisHeader() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.headerExists("Precedence"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.headerExists("Precedence"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m8.getUid(), m9.getUid());
@@ -834,7 +834,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void addressShouldReturnUidHavingRightExpeditorWhenFromIsSpecified() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.From, "murari.ksr@gmail.com"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.From, "murari.ksr@gmail.com"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m8.getUid());
@@ -846,7 +846,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.From, "murari"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.From, "murari"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m8.getUid());
@@ -858,7 +858,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.From, "gmail.com"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.From, "gmail.com"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m8.getUid());
@@ -870,7 +870,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.To, "ÃœsteliÄŸhan"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.To, "ÃœsteliÄŸhan"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m8.getUid());
@@ -878,7 +878,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void addressShouldReturnUidHavingRightRecipientWhenToIsSpecified() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.To, "root@listes.minet.net"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.To, "root@listes.minet.net"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid());
@@ -890,7 +890,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.To, "root"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.To, "root"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid());
@@ -902,7 +902,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.To, "listes.minet.net"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.To, "listes.minet.net"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid());
@@ -914,7 +914,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.Cc, "monkey@any.com"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.Cc, "monkey@any.com"));
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
     }
@@ -925,7 +925,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.Cc, "monkey"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.Cc, "monkey"));
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
     }
@@ -936,7 +936,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.Cc, "any.com"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.Cc, "any.com"));
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
     }
@@ -947,7 +947,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.Bcc, "monkey"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.Bcc, "monkey"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
@@ -959,7 +959,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.Bcc, "any.com"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.Bcc, "any.com"));
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
     }
@@ -970,7 +970,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .getSupportedSearchCapabilities()
             .contains(MailboxManager.SearchCapabilities.PartialEmailMatch));
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.address(AddressType.Bcc, "no@no.com"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.address(AddressType.Bcc, "no@no.com"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m9.getUid());
@@ -979,7 +979,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void uidShouldreturnExistingUidsOnTheGivenRanges() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m4.getUid()), new SearchQuery.UidRange(m6.getUid(), m7.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.uid(numericRanges));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m2.getUid(), m3.getUid(), m4.getUid(), m6.getUid(), m7.getUid());
@@ -988,7 +988,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     protected void uidShouldreturnEveryThing() throws Exception {
         SearchQuery.UidRange[] numericRanges = {};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.uid(numericRanges));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -996,9 +996,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void youShouldBeAbleToSpecifySeveralCriterionOnASingleQuery() throws Exception {
-        SearchQuery searchQuery = new SearchQuery();
-        searchQuery.andCriteria(SearchQuery.headerExists("Precedence"));
-        searchQuery.andCriteria(SearchQuery.modSeqGreaterThan(6L));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.headerExists("Precedence"), SearchQuery.modSeqGreaterThan(6L));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m6.getUid(), m8.getUid(), m9.getUid());
@@ -1006,7 +1004,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void andShouldReturnResultsMatchingBothRequests() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.and(
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.and(
             SearchQuery.headerExists("Precedence"),
             SearchQuery.modSeqGreaterThan(6L)));
 
@@ -1017,7 +1015,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     protected void orShouldReturnResultsMatchinganyRequests() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m4.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.or(
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.or(
             SearchQuery.uid(numericRanges),
             SearchQuery.modSeqGreaterThan(6L)));
 
@@ -1027,7 +1025,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void notShouldReturnResultsThatDoNotMatchAQuery() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(
+        SearchQuery searchQuery = SearchQuery.of(
             SearchQuery.not(SearchQuery.headerExists("Precedence")));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
@@ -1036,8 +1034,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void sortShouldOrderMessages() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival)));
+        SearchQuery searchQuery = SearchQuery.allSortedWith(new Sort(SortClause.Arrival));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m1.getUid(), m2.getUid(), m3.getUid(), m5.getUid(), m4.getUid(), m6.getUid(), m7.getUid(), m8.getUid(), m9.getUid());
@@ -1045,8 +1042,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void revertSortingShouldReturnElementsInAReversedOrder() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery searchQuery = SearchQuery.allSortedWith(new Sort(SortClause.Arrival, Order.REVERSE));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m9.getUid(), m8.getUid(), m7.getUid(), m6.getUid(), m4.getUid(), m5.getUid(), m3.getUid(), m2.getUid(), m1.getUid());
@@ -1054,10 +1050,11 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void headerDateAfterShouldWork() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(
-            SearchQuery.headerDateAfter("sentDate", new Date(1433408400000L), DateResolution.Second));
         // Date : 2015/06/04 11:00:00.000 ( Paris time zone )
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.headerDateAfter("sentDate", new Date(1433408400000L), DateResolution.Second))
+            .sorts(new Sort(SortClause.Arrival, Order.REVERSE))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m3.getUid(), m2.getUid());
@@ -1065,10 +1062,11 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void headerDateBeforeShouldWork() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(
-            SearchQuery.headerDateBefore("sentDate", new Date(1433109600000L), DateResolution.Day));
         // Date : 2015/06/01 00:00:00.000 ( Paris time zone )
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.headerDateBefore("sentDate", new Date(1433109600000L), DateResolution.Day))
+            .sorts(new Sort(SortClause.Arrival, Order.REVERSE))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m5.getUid());
@@ -1076,10 +1074,11 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void headerDateOnShouldWork() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(
-            SearchQuery.headerDateOn("sentDate", new Date(1433224800000L), DateResolution.Day));
         // Date : 2015/06/02 08:00:00.000 ( Paris time zone )
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival, Order.REVERSE)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.headerDateOn("sentDate", new Date(1433224800000L), DateResolution.Day))
+            .sorts(new Sort(SortClause.Arrival, Order.REVERSE))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m4.getUid(), m9.getUid());
@@ -1087,7 +1086,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     protected void mailsContainsShouldIncludeMailHavingAttachmentsMatchingTheRequest() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.mailContains("root mailing list"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.mailContains("root mailing list"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(m1.getUid(), m6.getUid());
@@ -1096,8 +1095,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     protected void sortOnCcShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.MailboxCc)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.MailboxCc))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m3.getUid(), m5.getUid(), m4.getUid(), m2.getUid());
@@ -1110,8 +1111,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     protected void sortOnFromShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.MailboxFrom)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.MailboxFrom))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m3.getUid(), m2.getUid(), m4.getUid(), m5.getUid());
@@ -1124,8 +1127,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     protected void sortOnToShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.MailboxTo)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.MailboxTo))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m5.getUid(), m3.getUid(), m2.getUid(), m4.getUid());
@@ -1138,8 +1143,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void sortOnSubjectShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.BaseSubject)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.BaseSubject))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m4.getUid(), m3.getUid(), m2.getUid(), m5.getUid());
@@ -1152,8 +1159,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void sortOnSizeShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Size)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.Size))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m2.getUid(), m3.getUid(), m5.getUid(), m4.getUid());
@@ -1166,8 +1175,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     protected void sortOnDisplayFromShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.DisplayFrom)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.DisplayFrom))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m4.getUid(), m3.getUid(), m5.getUid(), m2.getUid());
@@ -1180,8 +1191,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void sortOnDisplayToShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.DisplayTo)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.DisplayTo))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m3.getUid(), m2.getUid(), m4.getUid(), m5.getUid());
@@ -1194,8 +1207,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void sortOnSentDateShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.SentDate)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.SentDate))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m5.getUid(), m4.getUid(), m2.getUid(), m3.getUid());
@@ -1208,8 +1223,10 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void sortOnIdShouldWork() throws Exception {
         SearchQuery.UidRange[] numericRanges = {new SearchQuery.UidRange(m2.getUid(), m5.getUid())};
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.uid(numericRanges));
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Uid)));
+        SearchQuery searchQuery = SearchQuery.builder()
+            .andCriteria(SearchQuery.uid(numericRanges))
+            .sorts(new Sort(SortClause.Uid))
+            .build();
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m2.getUid(), m3.getUid(), m4.getUid(), m5.getUid());
@@ -1218,7 +1235,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnNoMailWhenNotMatching() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("unmatching"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("unmatching"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .isEmpty();
@@ -1227,7 +1244,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenFromMatches() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("spam.minet.net"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("spam.minet.net"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m1.getUid());
@@ -1236,7 +1253,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenMatches() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("root@listes.minet.net"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("root@listes.minet.net"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m1.getUid());
@@ -1245,7 +1262,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenToIsNotAnExactMatches() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("root"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("root"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m1.getUid());
@@ -1254,7 +1271,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenCcMatches() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("abc@abc.org"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("abc@abc.org"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m3.getUid());
@@ -1263,7 +1280,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenCcIsNotAExactMatch() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("monkey"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("monkey"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m5.getUid());
@@ -1272,7 +1289,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenBccMatches() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("monkey@any.com"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("monkey@any.com"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m5.getUid());
@@ -1281,7 +1298,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenBccIsNotAExactMatch() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("monkey"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("monkey"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m5.getUid());
@@ -1290,7 +1307,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenTextBodyMatches() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("reviewing work"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("reviewing work"));
 
         // text/plain contains: "We are reviewing work I did for this feature."
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
@@ -1300,7 +1317,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenTextBodyMatchesAndNonContinuousWords() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("reviewing feature"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("reviewing feature"));
         // 2: text/plain contains: "Issue Type: New Feature"
         // 3: text/plain contains: "We are reviewing work I did for this feature."
 
@@ -1311,7 +1328,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenTextBodyMatchesInsensitiveWords() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("reVieWing"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("reVieWing"));
         // text/plain contains: "We are reviewing work I did for this feature."
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
@@ -1321,7 +1338,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenTextBodyWithExtraUnindexedWords() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("a reviewing of the work"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("a reviewing of the work"));
         // text/plain contains: "We are reviewing work I did for this feature."
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
@@ -1331,7 +1348,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenHtmlBodyMatches() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("contains a banana"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("contains a banana"));
         // text/html contains: "This is a mail with beautifull html content which contains a banana."
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
@@ -1341,7 +1358,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenHtmlBodyMatchesWithStemming() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("contain banana"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("contain banana"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m7.getUid());
@@ -1350,7 +1367,7 @@ public abstract class AbstractMessageSearchIndexTest {
     @Test
     void searchWithTextShouldReturnMailsWhenHtmlBodyMatchesAndNonContinuousWords() throws Exception {
         assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text));
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.textContains("beautifull banana"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.textContains("beautifull banana"));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsExactly(m7.getUid());
@@ -1365,7 +1382,7 @@ public abstract class AbstractMessageSearchIndexTest {
             session).getId();
         await();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.mailContains("User message banana"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.mailContains("User message banana"));
 
         assertThat(messageSearchIndex.search(session, mailbox2, searchQuery))
             .containsExactly(messageWithBeautifulBananaAsTextAttachment.getUid());
@@ -1380,7 +1397,7 @@ public abstract class AbstractMessageSearchIndexTest {
             session).getId();
         await();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.attachmentContains("beautiful banana"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.attachmentContains("beautiful banana"));
 
         assertThat(messageSearchIndex.search(session, mailbox2, searchQuery))
             .containsExactly(messageWithBeautifulBananaAsTextAttachment.getUid());
@@ -1404,7 +1421,7 @@ public abstract class AbstractMessageSearchIndexTest {
             .appendMessage(MessageManager.AppendCommand.from(message), session).getId();
         await();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.attachmentContains("beautiful banana"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.attachmentContains("beautiful banana"));
 
         assertThat(messageSearchIndex.search(session, mailbox2, searchQuery))
             .containsExactly(messageWithBeautifulBananaAsPDFAttachment.getUid());
@@ -1412,8 +1429,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void sortShouldNotDiscardResultWhenSearchingFieldIsIdentical() throws Exception {
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.Arrival)));
+        SearchQuery searchQuery = SearchQuery.allSortedWith(new Sort(SortClause.Arrival));
 
         List<MessageId> actual = messageSearchIndex.search(
             session,
@@ -1457,8 +1473,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery();
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.SentDate)));
+        SearchQuery searchQuery = SearchQuery.allSortedWith(new Sort(SortClause.SentDate));
 
         assertThat(messageManager.search(searchQuery, session))
             .containsExactly(message2.getUid(),
@@ -1497,8 +1512,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery();
-        searchQuery.setSorts(ImmutableList.of(new Sort(SortClause.SentDate)));
+        SearchQuery searchQuery = SearchQuery.allSortedWith(new Sort(SortClause.SentDate));
 
         assertThat(messageManager.search(searchQuery, session))
             .containsExactly(message2.getUid(),
@@ -1508,8 +1522,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
     @Test
     void searchShouldRetrieveExactlyMatchingMimeMessageID() throws Exception {
-        SearchQuery searchQuery = new SearchQuery();
-        searchQuery.andCriteria(SearchQuery.mimeMessageID("<JI...@Atlassian.JIRA>"));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.mimeMessageID("<JI...@Atlassian.JIRA>"));
         // Correspond to mail.eml
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
@@ -1523,7 +1536,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         storeMailboxManager.copyMessages(MessageRange.all(), inboxMessageManager.getId(), newBoxId, session);
 
-        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery searchQuery = SearchQuery.matchAll();
 
         StoreMessageManager newBox = (StoreMessageManager) storeMailboxManager.getMailbox(newBoxId, session);
 
@@ -1559,7 +1572,7 @@ public abstract class AbstractMessageSearchIndexTest {
 
         await();
 
-        SearchQuery searchQuery = new SearchQuery(SearchQuery.attachmentFileName(fileName));
+        SearchQuery searchQuery = SearchQuery.of(SearchQuery.attachmentFileName(fileName));
 
         assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
             .containsOnly(mWithFileName.getUid());
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
index 2675934..0936cc6 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
@@ -546,7 +546,7 @@ public abstract class AbstractMailboxProcessor<R extends ImapRequest> extends Ab
         //      as above.  In the case where there have been no expunges, the server
         //      can ignore this data.
         if (metaData.getHighestModSeq().asLong() > changedSince) {
-            SearchQuery searchQuery = new SearchQuery();
+            SearchQuery.Builder searchQuery = SearchQuery.builder();
             SearchQuery.UidRange[] nRanges = new SearchQuery.UidRange[ranges.size()];
             Set<MessageUid> vanishedUids = new HashSet<>();
             for (int i = 0; i < ranges.size(); i++) {
@@ -568,7 +568,7 @@ public abstract class AbstractMailboxProcessor<R extends ImapRequest> extends Ab
             }
             searchQuery.andCriteria(SearchQuery.uid(nRanges));
             searchQuery.andCriteria(SearchQuery.modSeqGreaterThan(changedSince));
-            try (Stream<MessageUid> uids = mailbox.search(searchQuery, session)) {
+            try (Stream<MessageUid> uids = mailbox.search(searchQuery.build(), session)) {
                 uids.forEach(vanishedUids::remove);
             }
             UidRange[] vanishedIdRanges = uidRanges(MessageRange.toRanges(vanishedUids));
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
index c2ccf61..58e6889 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
@@ -263,16 +263,15 @@ public class SearchProcessor extends AbstractMailboxProcessor<SearchRequest> imp
         return highestModSeq;
     }
 
-
     private SearchQuery toQuery(SearchKey key, ImapSession session) throws MessageRangeException {
-        final SearchQuery result = new SearchQuery();
-        final SelectedMailbox selected = session.getSelected();
+        SearchQuery.Criterion criterion = toCriterion(key, session);
+        SearchQuery.Builder builder = SearchQuery.builder();
+        SelectedMailbox selected = session.getSelected();
         if (selected != null) {
-            result.addRecentMessageUids(selected.getRecent());
+            builder.addRecentMessageUids(selected.getRecent());
         }
-        final SearchQuery.Criterion criterion = toCriterion(key, session);
-        result.andCriteria(criterion);
-        return result;
+        return builder.andCriteria(criterion)
+            .build();
     }
 
     private SearchQuery.Criterion toCriterion(SearchKey key, ImapSession session) throws MessageRangeException {
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
index 5457960..2c07c2a 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
@@ -97,7 +97,7 @@ public class SelectedMailboxImpl implements SelectedMailbox, MailboxListener {
             .block();
 
         applicableFlags = messageManager.getApplicableFlags(mailboxSession);
-        try (Stream<MessageUid> stream = messageManager.search(new SearchQuery(SearchQuery.all()), mailboxSession)) {
+        try (Stream<MessageUid> stream = messageManager.search(SearchQuery.of(SearchQuery.all()), mailboxSession)) {
             uidMsnConverter.addAll(stream.collect(Guavate.toImmutableList()));
         }
     }
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java
index 3ee524a..1d48407 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java
@@ -457,8 +457,7 @@ public class SearchProcessorTest {
    
     private void check(SearchKey key, SearchQuery.Criterion criterion)
             throws Exception {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(criterion);
+        SearchQuery query = SearchQuery.of(criterion);
         check(key, query);
     }
 
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
index 722a90f..1ff48b2 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
@@ -38,7 +38,7 @@ import org.apache.james.jmap.draft.model.GetMessageListResponse;
 import org.apache.james.jmap.draft.model.GetMessagesRequest;
 import org.apache.james.jmap.draft.model.MethodCallId;
 import org.apache.james.jmap.draft.model.Number;
-import org.apache.james.jmap.draft.utils.FilterToSearchQuery;
+import org.apache.james.jmap.draft.utils.FilterToCriteria;
 import org.apache.james.jmap.draft.utils.SortConverter;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
@@ -167,17 +167,19 @@ public class GetMessageListMethod implements Method {
                 "implemented. Review your search request.");
         }
 
-        SearchQuery searchQuery = messageListRequest.getFilter()
-                .map(filter -> new FilterToSearchQuery().convert(filter))
-                .orElse(new SearchQuery());
+        SearchQuery.Builder searchQueryBuilder = SearchQuery.builder();
+
+            messageListRequest.getFilter()
+                .map(filter -> new FilterToCriteria().convert(filter).collect(Guavate.toImmutableList()))
+                .ifPresent(searchQueryBuilder::andCriteria);
         Set<MailboxId> inMailboxes = buildFilterMailboxesSet(messageListRequest.getFilter(), FilterCondition::getInMailboxes);
         Set<MailboxId> notInMailboxes = buildFilterMailboxesSet(messageListRequest.getFilter(), FilterCondition::getNotInMailboxes);
         List<SearchQuery.Sort> sorts = SortConverter.convertToSorts(messageListRequest.getSort());
         if (!sorts.isEmpty()) {
-            searchQuery.setSorts(sorts);
+            searchQueryBuilder.sorts(sorts);
         }
         return MultimailboxesSearchQuery
-                .from(searchQuery)
+                .from(searchQueryBuilder.build())
                 .inMailboxes(inMailboxes)
                 .notInMailboxes(notInMailboxes)
                 .build();
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/ReferenceUpdater.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/ReferenceUpdater.java
index 4abc540..2e48cd4 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/ReferenceUpdater.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/ReferenceUpdater.java
@@ -90,7 +90,7 @@ public class ReferenceUpdater {
     private void updateFlag(String messageId, MailboxSession session, Flags flag) throws MailboxException {
         int limit = 2;
         MultimailboxesSearchQuery searchByRFC822MessageId = MultimailboxesSearchQuery
-            .from(new SearchQuery(SearchQuery.mimeMessageID(messageId)))
+            .from(SearchQuery.of(SearchQuery.mimeMessageID(messageId)))
             .build();
         List<MessageId> references = Flux.from(mailboxManager.search(searchByRFC822MessageId, session, limit))
             .collectList().block();
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/FilterToSearchQuery.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/FilterToCriteria.java
similarity index 57%
rename from server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/FilterToSearchQuery.java
rename to server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/FilterToCriteria.java
index 6055a57..b3e4f32 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/FilterToSearchQuery.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/FilterToCriteria.java
@@ -21,6 +21,7 @@ package org.apache.james.jmap.draft.utils;
 
 import java.util.Date;
 import java.util.Optional;
+import java.util.stream.Stream;
 
 import javax.mail.Flags.Flag;
 
@@ -36,23 +37,21 @@ import org.apache.james.mailbox.model.SearchQuery.DateResolution;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
 
-public class FilterToSearchQuery {
+public class FilterToCriteria {
 
-    public SearchQuery convert(Filter filter) {
+    public Stream<Criterion> convert(Filter filter) {
         if (filter instanceof FilterCondition) {
             return convertCondition((FilterCondition) filter);
         }
         if (filter instanceof FilterOperator) {
-            SearchQuery searchQuery = new SearchQuery();
-            searchQuery.andCriteria(convertOperator((FilterOperator) filter));
-            return searchQuery;
+            return Stream.of(convertOperator((FilterOperator) filter));
         }
         throw new RuntimeException("Unknown filter: " + filter.getClass());
     }
 
-    private SearchQuery convertCondition(FilterCondition filter) {
-        SearchQuery searchQuery = new SearchQuery();
-        filter.getText().ifPresent(text -> searchQuery.andCriteria(
+    private Stream<Criterion> convertCondition(FilterCondition filter) {
+        ImmutableList.Builder<Criterion> builder = ImmutableList.builder();
+        filter.getText().ifPresent(text -> builder.add(
                 SearchQuery.or(ImmutableList.of(
                         SearchQuery.address(AddressType.From, text),
                         SearchQuery.address(AddressType.To, text),
@@ -63,29 +62,29 @@ public class FilterToSearchQuery {
                         SearchQuery.bodyContains(text),
                         SearchQuery.attachmentFileName(text)))
                 ));
-        filter.getFrom().ifPresent(from -> searchQuery.andCriteria(SearchQuery.address(AddressType.From, from)));
-        filter.getTo().ifPresent(to -> searchQuery.andCriteria(SearchQuery.address(AddressType.To, to)));
-        filter.getCc().ifPresent(cc -> searchQuery.andCriteria(SearchQuery.address(AddressType.Cc, cc)));
-        filter.getBcc().ifPresent(bcc -> searchQuery.andCriteria(SearchQuery.address(AddressType.Bcc, bcc)));
-        filter.getSubject().ifPresent(subject -> searchQuery.andCriteria(SearchQuery.headerContains("Subject", subject)));
-        filter.getAttachments().ifPresent(attachments ->  searchQuery.andCriteria(SearchQuery.attachmentContains(attachments)));
-        filter.getBody().ifPresent(body ->  searchQuery.andCriteria(SearchQuery.bodyContains(body)));
-        filter.getAfter().ifPresent(after -> searchQuery.andCriteria(SearchQuery.sentDateAfter(Date.from(after.toInstant()), DateResolution.Second)));
-        filter.getBefore().ifPresent(before -> searchQuery.andCriteria(SearchQuery.sentDateBefore(Date.from(before.toInstant()), DateResolution.Second)));
-        filter.getHeader().ifPresent(header -> searchQuery.andCriteria(SearchQuery.headerContains(header.getName(), header.getValue().orElse(null))));
-        filter.getIsAnswered().ifPresent(isAnswered -> searchQuery.andCriteria(SearchQuery.flag(Flag.ANSWERED, isAnswered)));
-        filter.getIsDraft().ifPresent(isDraft -> searchQuery.andCriteria(SearchQuery.flag(Flag.DRAFT, isDraft)));
-        filter.getIsFlagged().ifPresent(isFlagged -> searchQuery.andCriteria(SearchQuery.flag(Flag.FLAGGED, isFlagged)));
-        filter.getIsUnread().ifPresent(isUnread -> searchQuery.andCriteria(SearchQuery.flag(Flag.SEEN, !isUnread)));
-        filter.getIsForwarded().ifPresent(isForwarded -> searchQuery.andCriteria(SearchQuery.flagSet(Keyword.FORWARDED.getFlagName(), isForwarded)));
-        filter.getMaxSize().ifPresent(maxSize -> searchQuery.andCriteria(SearchQuery.sizeLessThan(maxSize.asLong())));
-        filter.getMinSize().ifPresent(minSize -> searchQuery.andCriteria(SearchQuery.sizeGreaterThan(minSize.asLong())));
-        filter.getHasAttachment().ifPresent(hasAttachment -> searchQuery.andCriteria(SearchQuery.hasAttachment(hasAttachment)));
-        filter.getHasKeyword().ifPresent(hasKeyword -> keywordQuery(hasKeyword, true).ifPresent(searchQuery::andCriteria));
-        filter.getNotKeyword().ifPresent(notKeyword -> keywordQuery(notKeyword, false).ifPresent(searchQuery::andCriteria));
-        filter.getAttachmentFileName().ifPresent(attachmentFileName -> searchQuery.andCriteria(SearchQuery.attachmentFileName(attachmentFileName)));
+        filter.getFrom().ifPresent(from -> builder.add(SearchQuery.address(AddressType.From, from)));
+        filter.getTo().ifPresent(to -> builder.add(SearchQuery.address(AddressType.To, to)));
+        filter.getCc().ifPresent(cc -> builder.add(SearchQuery.address(AddressType.Cc, cc)));
+        filter.getBcc().ifPresent(bcc -> builder.add(SearchQuery.address(AddressType.Bcc, bcc)));
+        filter.getSubject().ifPresent(subject -> builder.add(SearchQuery.headerContains("Subject", subject)));
+        filter.getAttachments().ifPresent(attachments ->  builder.add(SearchQuery.attachmentContains(attachments)));
+        filter.getBody().ifPresent(body ->  builder.add(SearchQuery.bodyContains(body)));
+        filter.getAfter().ifPresent(after -> builder.add(SearchQuery.sentDateAfter(Date.from(after.toInstant()), DateResolution.Second)));
+        filter.getBefore().ifPresent(before -> builder.add(SearchQuery.sentDateBefore(Date.from(before.toInstant()), DateResolution.Second)));
+        filter.getHeader().ifPresent(header -> builder.add(SearchQuery.headerContains(header.getName(), header.getValue().orElse(null))));
+        filter.getIsAnswered().ifPresent(isAnswered -> builder.add(SearchQuery.flag(Flag.ANSWERED, isAnswered)));
+        filter.getIsDraft().ifPresent(isDraft -> builder.add(SearchQuery.flag(Flag.DRAFT, isDraft)));
+        filter.getIsFlagged().ifPresent(isFlagged -> builder.add(SearchQuery.flag(Flag.FLAGGED, isFlagged)));
+        filter.getIsUnread().ifPresent(isUnread -> builder.add(SearchQuery.flag(Flag.SEEN, !isUnread)));
+        filter.getIsForwarded().ifPresent(isForwarded -> builder.add(SearchQuery.flagSet(Keyword.FORWARDED.getFlagName(), isForwarded)));
+        filter.getMaxSize().ifPresent(maxSize -> builder.add(SearchQuery.sizeLessThan(maxSize.asLong())));
+        filter.getMinSize().ifPresent(minSize -> builder.add(SearchQuery.sizeGreaterThan(minSize.asLong())));
+        filter.getHasAttachment().ifPresent(hasAttachment -> builder.add(SearchQuery.hasAttachment(hasAttachment)));
+        filter.getHasKeyword().ifPresent(hasKeyword -> keywordQuery(hasKeyword, true).ifPresent(builder::add));
+        filter.getNotKeyword().ifPresent(notKeyword -> keywordQuery(notKeyword, false).ifPresent(builder::add));
+        filter.getAttachmentFileName().ifPresent(attachmentFileName -> builder.add(SearchQuery.attachmentFileName(attachmentFileName)));
 
-        return searchQuery;
+        return builder.build().stream();
     }
 
     private Optional<Criterion> keywordQuery(String stringKeyword, boolean isSet) {
@@ -119,8 +118,7 @@ public class FilterToSearchQuery {
 
     private ImmutableList<Criterion> convertCriterias(FilterOperator filter) {
         return filter.getConditions().stream()
-            .map(this::convert)
-            .flatMap(sq -> sq.getCriterias().stream())
+            .flatMap(this::convert)
             .collect(Guavate.toImmutableList());
     }
 }
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java
index 823867d..b723f16 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java
@@ -107,7 +107,7 @@ public class ExtractMDNOriginalJMAPMessageId extends GenericMailet {
             MailboxSession session = mailboxManager.createSystemSession(usersRepository.getUsername(recipient));
             int limit = 1;
             MultimailboxesSearchQuery searchByRFC822MessageId = MultimailboxesSearchQuery
-                .from(new SearchQuery(SearchQuery.mimeMessageID(messageId)))
+                .from(SearchQuery.of(SearchQuery.mimeMessageID(messageId)))
                 .build();
             return Flux.from(mailboxManager.search(searchByRFC822MessageId, session, limit)).toStream().findFirst();
         } catch (MailboxException | UsersRepositoryException e) {
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/utils/FilterToCriteriaTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/utils/FilterToCriteriaTest.java
new file mode 100644
index 0000000..30d73ee
--- /dev/null
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/utils/FilterToCriteriaTest.java
@@ -0,0 +1,433 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.draft.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.time.ZonedDateTime;
+import java.util.Date;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.mail.Flags.Flag;
+
+import org.apache.james.jmap.draft.model.Filter;
+import org.apache.james.jmap.draft.model.FilterCondition;
+import org.apache.james.jmap.draft.model.FilterOperator;
+import org.apache.james.jmap.draft.model.Header;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.model.SearchQuery.AddressType;
+import org.apache.james.mailbox.model.SearchQuery.DateResolution;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class FilterToCriteriaTest {
+    private static final String FORWARDED = "forwarded";
+
+    @Test
+    public void filterConditionShouldThrowWhenUnknownFilter() {
+        Filter myFilter = (indentation -> null);
+        assertThatThrownBy(() -> new FilterToCriteria().convert(myFilter))
+            .isInstanceOf(RuntimeException.class)
+            .hasMessage("Unknown filter: " + myFilter.getClass());
+    }
+
+    @Test
+    public void filterConditionShouldMapEmptyWhenEmptyFilter() {
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder().build());
+
+        assertThat(criteria).isEmpty();
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenFrom() {
+        String from = "sender@james.org";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .from(from)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.address(AddressType.From, from));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenTo() {
+        String to = "recipient@james.org";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .to(to)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.address(AddressType.To, to));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenCc() {
+        String cc = "copy@james.org";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .cc(cc)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.address(AddressType.Cc, cc));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenHasAttachment() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+            .hasAttachment(true)
+            .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.hasAttachment());
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenHasNoAttachment() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+            .hasAttachment(false)
+            .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.hasNoAttachment());
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenBcc() {
+        String bcc = "blindcopy@james.org";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .bcc(bcc)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.address(AddressType.Bcc, bcc));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenSubject() {
+        String subject = "subject";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .subject(subject)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.headerContains("Subject", subject));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenBody() {
+        String body = "body";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .body(body)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.bodyContains(body));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenAttachments() {
+        String attachments = "attachments";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .attachments(attachments)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.attachmentContains(attachments));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenText() {
+        String text = "text";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .text(text)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.or(ImmutableList.of(
+            SearchQuery.address(AddressType.From, text),
+            SearchQuery.address(AddressType.To, text),
+            SearchQuery.address(AddressType.Cc, text),
+            SearchQuery.address(AddressType.Bcc, text),
+            SearchQuery.headerContains("Subject", text),
+            SearchQuery.bodyContains(text),
+            SearchQuery.attachmentContains(text),
+            SearchQuery.attachmentFileName(text))));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenAfter() {
+        ZonedDateTime after = ZonedDateTime.now();Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .after(after)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.sentDateAfter(Date.from(after.toInstant()), DateResolution.Second));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenBefore() {
+        ZonedDateTime before = ZonedDateTime.now();Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .before(before)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.sentDateBefore(Date.from(before.toInstant()), DateResolution.Second));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenIsAnswered() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .isAnswered(true)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsSet(Flag.ANSWERED));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenIsDraft() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .isDraft(true)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsSet(Flag.DRAFT));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenIsFlagged() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .isFlagged(true)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsSet(Flag.FLAGGED));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenIsUnread() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .isUnread(true)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsUnSet(Flag.SEEN));
+    }
+
+
+    @Test
+    public void filterConditionShouldMapWhenIsNotAnswered() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+            .isAnswered(false)
+            .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsUnSet(Flag.ANSWERED));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenIsNotDraft() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+            .isDraft(false)
+            .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsUnSet(Flag.DRAFT));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenIsNotFlagged() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+            .isFlagged(false)
+            .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsUnSet(Flag.FLAGGED));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenIsRead() {Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+            .isUnread(false)
+            .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsSet(Flag.SEEN));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenMaxSize() {
+        int maxSize = 123;Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .maxSize(maxSize)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.sizeLessThan(maxSize));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenMinSize() {
+        int minSize = 4;Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .minSize(minSize)
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.sizeGreaterThan(minSize));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenHeaderWithOneElement() {
+        String headerName = "name";Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .header(Header.from(ImmutableList.of(headerName)))
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.headerExists(headerName));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenHeaderWithTwoElements() {
+        String headerName = "name";
+        String headerValue = "value";
+
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .header(Header.from(ImmutableList.of(headerName, headerValue)))
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.headerContains(headerName, headerValue));
+    }
+
+    @Test
+    public void filterConditionShouldMapTwoConditions() {
+        String from = "sender@james.org";
+        String to = "recipient@james.org";Filter filter = FilterOperator.and(
+                FilterCondition.builder()
+                    .from(from)
+                    .build(),
+                FilterCondition.builder()
+                    .to(to)
+                    .build());
+
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(filter);
+
+        assertThat(criteria).containsExactly(SearchQuery.and(ImmutableList.of(
+            SearchQuery.address(AddressType.From, from),
+            SearchQuery.address(AddressType.To, to))));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenAndOperator() {
+        String from = "sender@james.org";
+        String to = "recipient@james.org";
+        String subject = "subject";
+
+        Filter complexFilter = FilterOperator.and(
+                FilterCondition.builder()
+                    .from(from)
+                    .to(to)
+                    .subject(subject)
+                    .build());
+
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(complexFilter);
+
+        assertThat(criteria).containsExactly(SearchQuery.and(ImmutableList.of(
+            SearchQuery.address(AddressType.From, from),
+            SearchQuery.address(AddressType.To, to),
+            SearchQuery.headerContains("Subject", subject))));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenOrOperator() {
+        String from = "sender@james.org";
+        String to = "recipient@james.org";
+        String subject = "subject";
+
+        Filter complexFilter = FilterOperator.or(
+                FilterCondition.builder()
+                    .from(from)
+                    .to(to)
+                    .subject(subject)
+                    .build());
+
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(complexFilter);
+
+        assertThat(criteria).containsExactly(SearchQuery.or(ImmutableList.of(
+            SearchQuery.address(AddressType.From, from),
+            SearchQuery.address(AddressType.To, to),
+            SearchQuery.headerContains("Subject", subject))));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenNotOperator() {
+        String from = "sender@james.org";
+        String to = "recipient@james.org";
+        String subject = "subject";
+
+        Filter complexFilter = FilterOperator.not(
+                FilterCondition.builder()
+                    .from(from)
+                    .to(to)
+                    .subject(subject)
+                    .build());
+
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(complexFilter);
+
+        assertThat(criteria).containsExactly(SearchQuery.not(ImmutableList.of(
+            SearchQuery.address(AddressType.From, from),
+            SearchQuery.address(AddressType.To, to),
+            SearchQuery.headerContains("Subject", subject))));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenComplexFilterTree() {
+        String from = "sender@james.org";
+        String to = "recipient@james.org";
+        String cc = "copy@james.org";
+
+        Filter complexFilter = FilterOperator.and(
+                FilterCondition.builder()
+                    .from(from)
+                    .build(),
+                FilterOperator.or(
+                    FilterOperator.not(
+                        FilterCondition.builder()
+                            .to(to)
+                            .build()),
+                    FilterCondition.builder()
+                        .cc(cc)
+                        .build()));
+
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(complexFilter);
+
+        assertThat(criteria).containsExactly(SearchQuery.and(ImmutableList.of(
+            SearchQuery.address(AddressType.From, from),
+            SearchQuery.or(ImmutableList.of(
+                SearchQuery.not(SearchQuery.address(AddressType.To, to)),
+                SearchQuery.address(AddressType.Cc, cc))))));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenHasKeyword() {
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .hasKeyword(Optional.of("$Flagged"))
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsSet(Flag.FLAGGED));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenHasKeywordWithUserFlag() {
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .hasKeyword(Optional.of(FORWARDED))
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsSet(FORWARDED));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenNotKeyword() {
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+            .notKeyword(Optional.of("$Flagged"))
+            .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsUnSet(Flag.FLAGGED));
+    }
+
+    @Test
+    public void filterConditionShouldMapWhenNotKeywordWithUserFlag() {
+        Stream<SearchQuery.Criterion> criteria = new FilterToCriteria().convert(FilterCondition.builder()
+                .notKeyword(Optional.of(FORWARDED))
+                .build());
+
+        assertThat(criteria).containsExactly(SearchQuery.flagIsUnSet(FORWARDED));
+    }
+
+    @Test
+    public void attachmentFileNameShouldMapWhenHasAttachmentFileName() {
+        String fileName = "file.gz";
+
+        assertThat(new FilterToCriteria().convert(FilterCondition.builder()
+            .attachmentFileName(Optional.of(fileName))
+            .build()))
+            .containsExactly(SearchQuery.attachmentFileName(fileName));
+    }
+}
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/utils/FilterToSearchQueryTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/utils/FilterToSearchQueryTest.java
deleted file mode 100644
index fba698b..0000000
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/utils/FilterToSearchQueryTest.java
+++ /dev/null
@@ -1,556 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.jmap.draft.utils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.time.ZonedDateTime;
-import java.util.Date;
-import java.util.Optional;
-
-import javax.mail.Flags.Flag;
-
-import org.apache.james.jmap.draft.model.Filter;
-import org.apache.james.jmap.draft.model.FilterCondition;
-import org.apache.james.jmap.draft.model.FilterOperator;
-import org.apache.james.jmap.draft.model.Header;
-import org.apache.james.mailbox.model.SearchQuery;
-import org.apache.james.mailbox.model.SearchQuery.AddressType;
-import org.apache.james.mailbox.model.SearchQuery.DateResolution;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-public class FilterToSearchQueryTest {
-    private static final String FORWARDED = "forwarded";
-
-    @Test
-    public void filterConditionShouldThrowWhenUnknownFilter() {
-        Filter myFilter = (indentation -> null);
-        assertThatThrownBy(() -> new FilterToSearchQuery().convert(myFilter))
-            .isInstanceOf(RuntimeException.class)
-            .hasMessage("Unknown filter: " + myFilter.getClass());
-    }
-
-    @Test
-    public void filterConditionShouldMapEmptyWhenEmptyFilter() {
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .build());
-
-        assertThat(searchQuery).isEqualTo(new SearchQuery());
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenFrom() {
-        String from = "sender@james.org";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.address(AddressType.From, from));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .from(from)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenTo() {
-        String to = "recipient@james.org";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.address(AddressType.To, to));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .to(to)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenCc() {
-        String cc = "copy@james.org";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.address(AddressType.Cc, cc));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .cc(cc)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenHasAttachment() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.hasAttachment());
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-            .hasAttachment(true)
-            .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenHasNoAttachment() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.hasNoAttachment());
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-            .hasAttachment(false)
-            .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenBcc() {
-        String bcc = "blindcopy@james.org";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.address(AddressType.Bcc, bcc));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .bcc(bcc)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenSubject() {
-        String subject = "subject";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.headerContains("Subject", subject));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .subject(subject)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenBody() {
-        String body = "body";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.bodyContains(body));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .body(body)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenAttachments() {
-        String attachments = "attachments";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.attachmentContains(attachments));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .attachments(attachments)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenText() {
-        String text = "text";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.or(ImmutableList.of(
-                SearchQuery.address(AddressType.From, text),
-                SearchQuery.address(AddressType.To, text),
-                SearchQuery.address(AddressType.Cc, text),
-                SearchQuery.address(AddressType.Bcc, text),
-                SearchQuery.headerContains("Subject", text),
-                SearchQuery.bodyContains(text),
-                SearchQuery.attachmentContains(text),
-                SearchQuery.attachmentFileName(text))));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .text(text)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenAfter() {
-        ZonedDateTime after = ZonedDateTime.now();
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.sentDateAfter(Date.from(after.toInstant()), DateResolution.Second));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .after(after)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenBefore() {
-        ZonedDateTime before = ZonedDateTime.now();
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.sentDateBefore(Date.from(before.toInstant()), DateResolution.Second));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .before(before)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenIsAnswered() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(Flag.ANSWERED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .isAnswered(true)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenIsDraft() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(Flag.DRAFT));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .isDraft(true)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenIsFlagged() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(Flag.FLAGGED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .isFlagged(true)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenIsUnread() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(Flag.SEEN));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .isUnread(true)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-
-    @Test
-    public void filterConditionShouldMapWhenIsNotAnswered() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(Flag.ANSWERED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-            .isAnswered(false)
-            .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenIsNotDraft() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(Flag.DRAFT));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-            .isDraft(false)
-            .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenIsNotFlagged() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(Flag.FLAGGED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-            .isFlagged(false)
-            .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenIsRead() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(Flag.SEEN));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-            .isUnread(false)
-            .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenMaxSize() {
-        int maxSize = 123;
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.sizeLessThan(maxSize));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .maxSize(maxSize)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenMinSize() {
-        int minSize = 4;
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.sizeGreaterThan(minSize));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .minSize(minSize)
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenHeaderWithOneElement() {
-        String headerName = "name";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.headerExists(headerName));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .header(Header.from(ImmutableList.of(headerName)))
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenHeaderWithTwoElements() {
-        String headerName = "name";
-        String headerValue = "value";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.headerContains(headerName, headerValue));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .header(Header.from(ImmutableList.of(headerName, headerValue)))
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapTwoConditions() {
-        String from = "sender@james.org";
-        String to = "recipient@james.org";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.and(ImmutableList.of(
-                SearchQuery.address(AddressType.From, from),
-                SearchQuery.address(AddressType.To, to))));
-
-        Filter filter = FilterOperator.and(
-                FilterCondition.builder()
-                    .from(from)
-                    .build(),
-                FilterCondition.builder()
-                    .to(to)
-                    .build());
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(filter);
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenAndOperator() {
-        String from = "sender@james.org";
-        String to = "recipient@james.org";
-        String subject = "subject";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.and(ImmutableList.of(
-                SearchQuery.address(AddressType.From, from),
-                SearchQuery.address(AddressType.To, to),
-                SearchQuery.headerContains("Subject", subject))));
-
-        Filter complexFilter = FilterOperator.and(
-                FilterCondition.builder()
-                    .from(from)
-                    .to(to)
-                    .subject(subject)
-                    .build());
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(complexFilter);
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenOrOperator() {
-        String from = "sender@james.org";
-        String to = "recipient@james.org";
-        String subject = "subject";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.or(ImmutableList.of(
-                SearchQuery.address(AddressType.From, from),
-                SearchQuery.address(AddressType.To, to),
-                SearchQuery.headerContains("Subject", subject))));
-
-        Filter complexFilter = FilterOperator.or(
-                FilterCondition.builder()
-                    .from(from)
-                    .to(to)
-                    .subject(subject)
-                    .build());
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(complexFilter);
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenNotOperator() {
-        String from = "sender@james.org";
-        String to = "recipient@james.org";
-        String subject = "subject";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.not(ImmutableList.of(
-                SearchQuery.address(AddressType.From, from),
-                SearchQuery.address(AddressType.To, to),
-                SearchQuery.headerContains("Subject", subject))));
-
-        Filter complexFilter = FilterOperator.not(
-                FilterCondition.builder()
-                    .from(from)
-                    .to(to)
-                    .subject(subject)
-                    .build());
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(complexFilter);
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenComplexFilterTree() {
-        String from = "sender@james.org";
-        String to = "recipient@james.org";
-        String cc = "copy@james.org";
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.and(ImmutableList.of(
-                SearchQuery.address(AddressType.From, from),
-                SearchQuery.or(ImmutableList.of(
-                        SearchQuery.not(SearchQuery.address(AddressType.To, to)),
-                        SearchQuery.address(AddressType.Cc, cc))
-                        )
-                )));
-
-        Filter complexFilter = FilterOperator.and(
-                FilterCondition.builder()
-                    .from(from)
-                    .build(),
-                FilterOperator.or(
-                    FilterOperator.not(
-                        FilterCondition.builder()
-                            .to(to)
-                            .build()),
-                    FilterCondition.builder()
-                        .cc(cc)
-                        .build()
-                ));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(complexFilter);
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenHasKeyword() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(Flag.FLAGGED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .hasKeyword(Optional.of("$Flagged"))
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenHasKeywordWithUserFlag() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsSet(FORWARDED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .hasKeyword(Optional.of(FORWARDED))
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenNotKeyword() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(Flag.FLAGGED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-            .notKeyword(Optional.of("$Flagged"))
-            .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void filterConditionShouldMapWhenNotKeywordWithUserFlag() {
-        SearchQuery expectedSearchQuery = new SearchQuery();
-        expectedSearchQuery.andCriteria(SearchQuery.flagIsUnSet(FORWARDED));
-
-        SearchQuery searchQuery = new FilterToSearchQuery().convert(FilterCondition.builder()
-                .notKeyword(Optional.of(FORWARDED))
-                .build());
-
-        assertThat(searchQuery).isEqualTo(expectedSearchQuery);
-    }
-
-    @Test
-    public void attachmentFileNameShouldMapWhenHasAttachmentFileName() {
-        String fileName = "file.gz";
-
-        SearchQuery expectedResult = new SearchQuery(SearchQuery.attachmentFileName(fileName));
-
-        assertThat(new FilterToSearchQuery().convert(FilterCondition.builder()
-            .attachmentFileName(Optional.of(fileName))
-            .build()))
-            .isEqualTo(expectedResult);
-    }
-}
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java
index 3e7dcb7..4a4fc5a 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java
@@ -2262,7 +2262,7 @@ class DeletedMessagesVaultRoutesTest {
         MailboxSession session = mailboxManager.createSystemSession(username);
         int limitToOneMessage = 1;
 
-        return !Flux.from(mailboxManager.search(MultimailboxesSearchQuery.from(new SearchQuery()).build(), session, limitToOneMessage))
+        return !Flux.from(mailboxManager.search(MultimailboxesSearchQuery.from(SearchQuery.of()).build(), session, limitToOneMessage))
             .collectList().block()
             .isEmpty();
     }


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