You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2023/12/06 08:13:02 UTC

(james-project) 01/03: JAMES-2586 [PGSQL] Implement correctly FetchType

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

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

commit 6b7568324842a18d1859d976e8f421faf53a69e7
Author: Tung Tran <vt...@linagora.com>
AuthorDate: Mon Dec 4 12:05:42 2023 +0700

    JAMES-2586 [PGSQL] Implement correctly FetchType
---
 .../james/backends/postgres/PostgresCommons.java   |   7 +-
 .../postgres/mail/PostgresMessageMapper.java       |  44 +++---
 .../mail/dao/PostgresMailboxMessageDAO.java        |  50 ++++---
 .../mail/dao/PostgresMailboxMessageDAOUtils.java   |  37 +++---
 .../dao/PostgresMailboxMessageFetchStrategy.java   | 147 +++++++++++++++++++++
 5 files changed, 217 insertions(+), 68 deletions(-)

diff --git a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresCommons.java b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresCommons.java
index ae4b8ebf5e..5ffb190525 100644
--- a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresCommons.java
+++ b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresCommons.java
@@ -49,11 +49,10 @@ public class PostgresCommons {
         DataType<String[]> STRING_ARRAY = SQLDataType.CLOB.getArrayDataType();
     }
 
-    public interface SimpleTableField {
-        Field<Object> of(Table<Record> table, Field<?> field);
-    }
 
-    public static final SimpleTableField TABLE_FIELD = (table, field) -> DSL.field(table.getName() + "." + field.getName());
+    public static <T> Field<T> tableField(Table<Record> table, Field<T> field) {
+        return DSL.field(table.getName() + "." + field.getName(), field.getDataType());
+    }
 
     public static final Function<Date, LocalDateTime> DATE_TO_LOCAL_DATE_TIME = date -> Optional.ofNullable(date)
         .map(value -> LocalDateTime.ofInstant(value.toInstant(), ZoneOffset.UTC))
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMessageMapper.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMessageMapper.java
index 1a6787d5c4..101118676a 100644
--- a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMessageMapper.java
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresMessageMapper.java
@@ -128,39 +128,41 @@ public class PostgresMessageMapper implements MessageMapper {
 
     @Override
     public Flux<MailboxMessage> findInMailboxReactive(Mailbox mailbox, MessageRange messageRange, FetchType fetchType, int limitAsInt) {
+        Flux<Pair<SimpleMailboxMessage.Builder, String>> fetchMessageWithoutFullContentPublisher = fetchMessageWithoutFullContent(mailbox, messageRange, fetchType, limitAsInt);
+        if (fetchType == FetchType.FULL) {
+            return fetchMessageWithoutFullContentPublisher
+                .flatMap(messageBuilderAndBlobId -> {
+                    SimpleMailboxMessage.Builder messageBuilder = messageBuilderAndBlobId.getLeft();
+                    String blobIdAsString = messageBuilderAndBlobId.getRight();
+                    return retrieveFullContent(blobIdAsString)
+                        .map(content -> messageBuilder.content(content).build());
+                })
+                .sort(Comparator.comparing(MailboxMessage::getUid))
+                .map(message -> message);
+        } else {
+            return fetchMessageWithoutFullContentPublisher
+                .map(messageBuilderAndBlobId -> messageBuilderAndBlobId.getLeft().build());
+        }
+    }
+
+    private Flux<Pair<SimpleMailboxMessage.Builder, String>> fetchMessageWithoutFullContent(Mailbox mailbox, MessageRange messageRange, FetchType fetchType, int limitAsInt) {
         return Mono.just(messageRange)
             .flatMapMany(range -> {
                 Limit limit = Limit.from(limitAsInt);
                 switch (messageRange.getType()) {
                     case ALL:
-                        return mailboxMessageDAO.findMessagesByMailboxId((PostgresMailboxId) mailbox.getMailboxId(), limit);
+                        return mailboxMessageDAO.findMessagesByMailboxId((PostgresMailboxId) mailbox.getMailboxId(), limit, fetchType);
                     case FROM:
-                        return mailboxMessageDAO.findMessagesByMailboxIdAndAfterUID((PostgresMailboxId) mailbox.getMailboxId(), range.getUidFrom(), limit);
+                        return mailboxMessageDAO.findMessagesByMailboxIdAndAfterUID((PostgresMailboxId) mailbox.getMailboxId(), range.getUidFrom(), limit, fetchType);
                     case ONE:
-                        return mailboxMessageDAO.findMessageByMailboxIdAndUid((PostgresMailboxId) mailbox.getMailboxId(), range.getUidFrom())
+                        return mailboxMessageDAO.findMessageByMailboxIdAndUid((PostgresMailboxId) mailbox.getMailboxId(), range.getUidFrom(), fetchType)
                             .flatMapMany(Flux::just);
                     case RANGE:
-                        return mailboxMessageDAO.findMessagesByMailboxIdAndBetweenUIDs((PostgresMailboxId) mailbox.getMailboxId(), range.getUidFrom(), range.getUidTo(), limit);
+                        return mailboxMessageDAO.findMessagesByMailboxIdAndBetweenUIDs((PostgresMailboxId) mailbox.getMailboxId(), range.getUidFrom(), range.getUidTo(), limit, fetchType);
                     default:
                         throw new RuntimeException("Unknown MessageRange range " + range.getType());
                 }
-            }).flatMap(messageBuilderAndBlobId -> {
-                SimpleMailboxMessage.Builder messageBuilder = messageBuilderAndBlobId.getLeft();
-                String blobIdAsString = messageBuilderAndBlobId.getRight();
-                switch (fetchType) {
-                    case METADATA:
-                    case ATTACHMENTS_METADATA:
-                    case HEADERS:
-                        return Mono.just(messageBuilder.build());
-                    case FULL:
-                        return retrieveFullContent(blobIdAsString)
-                            .map(content -> messageBuilder.content(content).build());
-                    default:
-                        return Flux.error(new RuntimeException("Unknown FetchType " + fetchType));
-                }
-            })
-            .sort(Comparator.comparing(MailboxMessage::getUid))
-            .map(message -> message);
+            });
     }
 
     private Mono<Content> retrieveFullContent(String blobIdString) {
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAO.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAO.java
index cbcba2943e..48f93a912e 100644
--- a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAO.java
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAO.java
@@ -22,8 +22,8 @@ package org.apache.james.mailbox.postgres.mail.dao;
 
 import static org.apache.james.backends.postgres.PostgresCommons.DATE_TO_LOCAL_DATE_TIME;
 import static org.apache.james.backends.postgres.PostgresCommons.IN_CLAUSE_MAX_SIZE;
-import static org.apache.james.backends.postgres.PostgresCommons.TABLE_FIELD;
 import static org.apache.james.backends.postgres.PostgresCommons.UNNEST_FIELD;
+import static org.apache.james.backends.postgres.PostgresCommons.tableField;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.BLOB_ID;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.INTERNAL_DATE;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.SIZE;
@@ -42,9 +42,9 @@ import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.Messa
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable.THREAD_ID;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable.USER_FLAGS;
 import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.BOOLEAN_FLAGS_MAPPING;
+import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.FETCH_TYPE_TO_FETCH_STRATEGY;
 import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.MESSAGE_METADATA_FIELDS_REQUIRE;
 import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.RECORD_TO_COMPOSED_MESSAGE_ID_WITH_META_DATA_FUNCTION;
-import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.RECORD_TO_MAILBOX_MESSAGE_BUILDER_FUNCTION;
 import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.RECORD_TO_MESSAGE_METADATA_FUNCTION;
 import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.RECORD_TO_MESSAGE_UID_FUNCTION;
 
@@ -66,6 +66,8 @@ import org.apache.james.mailbox.model.UpdatedFlags;
 import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.postgres.PostgresMessageId;
 import org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable;
+import org.apache.james.mailbox.store.mail.MessageMapper;
+import org.apache.james.mailbox.store.mail.MessageMapper.FetchType;
 import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
 import org.apache.james.util.streams.Limit;
@@ -89,7 +91,7 @@ import reactor.core.publisher.Mono;
 public class PostgresMailboxMessageDAO {
 
     private static final TableOnConditionStep<Record> MESSAGES_JOIN_MAILBOX_MESSAGES_CONDITION_STEP = TABLE_NAME.join(MessageTable.TABLE_NAME)
-        .on(TABLE_FIELD.of(TABLE_NAME, MESSAGE_ID).eq(TABLE_FIELD.of(MessageTable.TABLE_NAME, MessageTable.MESSAGE_ID)));
+        .on(tableField(TABLE_NAME, MESSAGE_ID).eq(tableField(MessageTable.TABLE_NAME, MessageTable.MESSAGE_ID)));
 
     public static final SortField<Long> DEFAULT_SORT_ORDER_BY = MESSAGE_UID.asc();
 
@@ -163,8 +165,9 @@ public class PostgresMailboxMessageDAO {
             .where(MAILBOX_ID.eq(mailboxId.asUuid()))));
     }
 
-    public Flux<Pair<SimpleMailboxMessage.Builder, String>> findMessagesByMailboxId(PostgresMailboxId mailboxId, Limit limit) {
-        Function<DSLContext, SelectSeekStep1<Record, Long>> queryWithoutLimit = dslContext -> dslContext.select()
+    public Flux<Pair<SimpleMailboxMessage.Builder, String>> findMessagesByMailboxId(PostgresMailboxId mailboxId, Limit limit, MessageMapper.FetchType fetchType) {
+        PostgresMailboxMessageFetchStrategy fetchStrategy = FETCH_TYPE_TO_FETCH_STRATEGY.apply(fetchType);
+        Function<DSLContext, SelectSeekStep1<Record, Long>> queryWithoutLimit = dslContext -> dslContext.select(fetchStrategy.fetchFields())
             .from(MESSAGES_JOIN_MAILBOX_MESSAGES_CONDITION_STEP)
             .where(MAILBOX_ID.eq(mailboxId.asUuid()))
             .orderBy(DEFAULT_SORT_ORDER_BY);
@@ -172,11 +175,12 @@ public class PostgresMailboxMessageDAO {
         return postgresExecutor.executeRows(dslContext -> limit.getLimit()
                 .map(limitValue -> Flux.from(queryWithoutLimit.andThen(step -> step.limit(limitValue)).apply(dslContext)))
                 .orElse(Flux.from(queryWithoutLimit.apply(dslContext))))
-            .map(record -> Pair.of(RECORD_TO_MAILBOX_MESSAGE_BUILDER_FUNCTION.apply(record), record.get(BLOB_ID)));
+            .map(record -> Pair.of(fetchStrategy.toMessageBuilder().apply(record), record.get(BLOB_ID)));
     }
 
-    public Flux<Pair<SimpleMailboxMessage.Builder, String>> findMessagesByMailboxIdAndBetweenUIDs(PostgresMailboxId mailboxId, MessageUid from, MessageUid to, Limit limit) {
-        Function<DSLContext, SelectSeekStep1<Record, Long>> queryWithoutLimit = dslContext -> dslContext.select()
+    public Flux<Pair<SimpleMailboxMessage.Builder, String>> findMessagesByMailboxIdAndBetweenUIDs(PostgresMailboxId mailboxId, MessageUid from, MessageUid to, Limit limit, FetchType fetchType) {
+        PostgresMailboxMessageFetchStrategy fetchStrategy = FETCH_TYPE_TO_FETCH_STRATEGY.apply(fetchType);
+        Function<DSLContext, SelectSeekStep1<Record, Long>> queryWithoutLimit = dslContext -> dslContext.select(fetchStrategy.fetchFields())
             .from(MESSAGES_JOIN_MAILBOX_MESSAGES_CONDITION_STEP)
             .where(MAILBOX_ID.eq(mailboxId.asUuid()))
             .and(MESSAGE_UID.greaterOrEqual(from.asLong()))
@@ -186,19 +190,21 @@ public class PostgresMailboxMessageDAO {
         return postgresExecutor.executeRows(dslContext -> limit.getLimit()
                 .map(limitValue -> Flux.from(queryWithoutLimit.andThen(step -> step.limit(limitValue)).apply(dslContext)))
                 .orElse(Flux.from(queryWithoutLimit.apply(dslContext))))
-            .map(record -> Pair.of(RECORD_TO_MAILBOX_MESSAGE_BUILDER_FUNCTION.apply(record), record.get(BLOB_ID)));
+            .map(record -> Pair.of(fetchStrategy.toMessageBuilder().apply(record), record.get(BLOB_ID)));
     }
 
-    public Mono<Pair<SimpleMailboxMessage.Builder, String>> findMessageByMailboxIdAndUid(PostgresMailboxId mailboxId, MessageUid uid) {
-        return postgresExecutor.executeRow(dslContext -> Mono.from(dslContext.select()
+    public Mono<Pair<SimpleMailboxMessage.Builder, String>> findMessageByMailboxIdAndUid(PostgresMailboxId mailboxId, MessageUid uid, FetchType fetchType) {
+        PostgresMailboxMessageFetchStrategy fetchStrategy = FETCH_TYPE_TO_FETCH_STRATEGY.apply(fetchType);
+        return postgresExecutor.executeRow(dslContext -> Mono.from(dslContext.select(fetchStrategy.fetchFields())
                 .from(MESSAGES_JOIN_MAILBOX_MESSAGES_CONDITION_STEP)
                 .where(MAILBOX_ID.eq(mailboxId.asUuid()))
                 .and(MESSAGE_UID.eq(uid.asLong()))))
-            .map(record -> Pair.of(RECORD_TO_MAILBOX_MESSAGE_BUILDER_FUNCTION.apply(record), record.get(BLOB_ID)));
+            .map(record -> Pair.of(fetchStrategy.toMessageBuilder().apply(record), record.get(BLOB_ID)));
     }
 
-    public Flux<Pair<SimpleMailboxMessage.Builder, String>> findMessagesByMailboxIdAndAfterUID(PostgresMailboxId mailboxId, MessageUid from, Limit limit) {
-        Function<DSLContext, SelectSeekStep1<Record, Long>> queryWithoutLimit = dslContext -> dslContext.select()
+    public Flux<Pair<SimpleMailboxMessage.Builder, String>> findMessagesByMailboxIdAndAfterUID(PostgresMailboxId mailboxId, MessageUid from, Limit limit, FetchType fetchType) {
+        PostgresMailboxMessageFetchStrategy fetchStrategy = FETCH_TYPE_TO_FETCH_STRATEGY.apply(fetchType);
+        Function<DSLContext, SelectSeekStep1<Record, Long>> queryWithoutLimit = dslContext -> dslContext.select(fetchStrategy.fetchFields())
             .from(MESSAGES_JOIN_MAILBOX_MESSAGES_CONDITION_STEP)
             .where(MAILBOX_ID.eq(mailboxId.asUuid()))
             .and(MESSAGE_UID.greaterOrEqual(from.asLong()))
@@ -207,16 +213,18 @@ public class PostgresMailboxMessageDAO {
         return postgresExecutor.executeRows(dslContext -> limit.getLimit()
                 .map(limitValue -> Flux.from(queryWithoutLimit.andThen(step -> step.limit(limitValue)).apply(dslContext)))
                 .orElse(Flux.from(queryWithoutLimit.apply(dslContext))))
-            .map(record -> Pair.of(RECORD_TO_MAILBOX_MESSAGE_BUILDER_FUNCTION.apply(record), record.get(BLOB_ID)));
+            .map(record -> Pair.of(fetchStrategy.toMessageBuilder().apply(record), record.get(BLOB_ID)));
     }
 
     public Flux<SimpleMailboxMessage.Builder> findMessagesByMailboxIdAndUIDs(PostgresMailboxId mailboxId, List<MessageUid> uids) {
-        Function<List<MessageUid>, Flux<SimpleMailboxMessage.Builder>> queryPublisherFunction = uidsToFetch -> postgresExecutor.executeRows(dslContext -> Flux.from(dslContext.select()
-                .from(MESSAGES_JOIN_MAILBOX_MESSAGES_CONDITION_STEP)
-                .where(MAILBOX_ID.eq(mailboxId.asUuid()))
-                .and(MESSAGE_UID.in(uidsToFetch.stream().map(MessageUid::asLong).toArray(Long[]::new)))
-                .orderBy(DEFAULT_SORT_ORDER_BY)))
-            .map(RECORD_TO_MAILBOX_MESSAGE_BUILDER_FUNCTION);
+        PostgresMailboxMessageFetchStrategy fetchStrategy = PostgresMailboxMessageFetchStrategy.METADATA;
+        Function<List<MessageUid>, Flux<SimpleMailboxMessage.Builder>> queryPublisherFunction =
+            uidsToFetch -> postgresExecutor.executeRows(dslContext -> Flux.from(dslContext.select(fetchStrategy.fetchFields())
+                    .from(MESSAGES_JOIN_MAILBOX_MESSAGES_CONDITION_STEP)
+                    .where(MAILBOX_ID.eq(mailboxId.asUuid()))
+                    .and(MESSAGE_UID.in(uidsToFetch.stream().map(MessageUid::asLong).toArray(Long[]::new)))
+                    .orderBy(DEFAULT_SORT_ORDER_BY)))
+                .map(fetchStrategy.toMessageBuilder());
 
         if (uids.size() <= IN_CLAUSE_MAX_SIZE) {
             return queryPublisherFunction.apply(uids);
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAOUtils.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAOUtils.java
index f69021d3bb..65404964a4 100644
--- a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAOUtils.java
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageDAOUtils.java
@@ -20,7 +20,6 @@
 package org.apache.james.mailbox.postgres.mail.dao;
 
 import static org.apache.james.backends.postgres.PostgresCommons.LOCAL_DATE_TIME_DATE_FUNCTION;
-import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.BODY_START_OCTET;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.CONTENT_DESCRIPTION;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.CONTENT_DISPOSITION_PARAMETERS;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.CONTENT_DISPOSITION_TYPE;
@@ -30,7 +29,6 @@ import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.Messa
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.CONTENT_MD5;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.CONTENT_TRANSFER_ENCODING;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.CONTENT_TYPE_PARAMETERS;
-import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.HEADER_CONTENT;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.INTERNAL_DATE;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.SIZE;
 import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable.IS_ANSWERED;
@@ -49,9 +47,7 @@ import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.Messa
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
-import java.time.LocalDateTime;
 import java.util.Arrays;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -69,9 +65,9 @@ import org.apache.james.mailbox.model.ThreadId;
 import org.apache.james.mailbox.postgres.PostgresMailboxId;
 import org.apache.james.mailbox.postgres.PostgresMessageId;
 import org.apache.james.mailbox.postgres.mail.PostgresMessageModule;
+import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.mail.model.impl.Properties;
 import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
-import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
 import org.jooq.Field;
 import org.jooq.Record;
 
@@ -156,8 +152,8 @@ interface PostgresMailboxMessageDAOUtils {
         property.setContentTransferEncoding(record.get(CONTENT_TRANSFER_ENCODING));
         property.setContentLocation(record.get(CONTENT_LOCATION));
         property.setContentLanguage(Optional.ofNullable(record.get(CONTENT_LANGUAGE)).map(List::of).orElse(null));
-        property.setContentDispositionParameters(record.get(CONTENT_DISPOSITION_PARAMETERS, LinkedHashMap.class));
-        property.setContentTypeParameters(record.get(CONTENT_TYPE_PARAMETERS, LinkedHashMap.class));
+        property.setContentDispositionParameters(record.get(CONTENT_DISPOSITION_PARAMETERS).data());
+        property.setContentTypeParameters(record.get(CONTENT_TYPE_PARAMETERS).data());
         return property.build();
     };
 
@@ -173,19 +169,16 @@ interface PostgresMailboxMessageDAOUtils {
         }
     };
 
-    Function<Record, SimpleMailboxMessage.Builder> RECORD_TO_MAILBOX_MESSAGE_BUILDER_FUNCTION = record -> SimpleMailboxMessage.builder()
-        .messageId(PostgresMessageId.Factory.of(record.get(MESSAGE_ID)))
-        .mailboxId(PostgresMailboxId.of(record.get(MAILBOX_ID)))
-        .uid(MessageUid.of(record.get(MESSAGE_UID)))
-        .modseq(ModSeq.of(record.get(MOD_SEQ)))
-        .threadId(RECORD_TO_THREAD_ID_FUNCTION.apply(record))
-        .internalDate(LOCAL_DATE_TIME_DATE_FUNCTION.apply(record.get(PostgresMessageModule.MessageTable.INTERNAL_DATE, LocalDateTime.class)))
-        .saveDate(LOCAL_DATE_TIME_DATE_FUNCTION.apply(record.get(SAVE_DATE, LocalDateTime.class)))
-        .flags(RECORD_TO_FLAGS_FUNCTION.apply(record))
-        .size(record.get(PostgresMessageModule.MessageTable.SIZE))
-        .bodyStartOctet(record.get(BODY_START_OCTET))
-        .content(BYTE_TO_CONTENT_FUNCTION.apply(record.get(HEADER_CONTENT)))
-        .properties(RECORD_TO_PROPERTIES_FUNCTION.apply(record));
-
-
+    Function<MessageMapper.FetchType, PostgresMailboxMessageFetchStrategy> FETCH_TYPE_TO_FETCH_STRATEGY = fetchType -> {
+        switch (fetchType) {
+            case METADATA:
+            case ATTACHMENTS_METADATA:
+                return PostgresMailboxMessageFetchStrategy.METADATA;
+            case HEADERS:
+            case FULL:
+                return PostgresMailboxMessageFetchStrategy.FULL;
+            default:
+                throw new RuntimeException("Unknown FetchType " + fetchType);
+        }
+    };
 }
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageFetchStrategy.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageFetchStrategy.java
new file mode 100644
index 0000000000..4aef7b69ef
--- /dev/null
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxMessageFetchStrategy.java
@@ -0,0 +1,147 @@
+/****************************************************************
+ * 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.mailbox.postgres.mail.dao;
+
+import static org.apache.james.backends.postgres.PostgresCommons.LOCAL_DATE_TIME_DATE_FUNCTION;
+import static org.apache.james.backends.postgres.PostgresCommons.tableField;
+import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable;
+import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.BODY_START_OCTET;
+import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageTable.HEADER_CONTENT;
+import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable.MAILBOX_ID;
+import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable.MESSAGE_UID;
+import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable.MOD_SEQ;
+import static org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable.SAVE_DATE;
+import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.BYTE_TO_CONTENT_FUNCTION;
+import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.RECORD_TO_FLAGS_FUNCTION;
+import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.RECORD_TO_PROPERTIES_FUNCTION;
+import static org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAOUtils.RECORD_TO_THREAD_ID_FUNCTION;
+
+import java.time.LocalDateTime;
+import java.util.function.Function;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.ModSeq;
+import org.apache.james.mailbox.model.Content;
+import org.apache.james.mailbox.postgres.PostgresMailboxId;
+import org.apache.james.mailbox.postgres.PostgresMessageId;
+import org.apache.james.mailbox.postgres.mail.PostgresMessageModule;
+import org.apache.james.mailbox.postgres.mail.PostgresMessageModule.MessageToMailboxTable;
+import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
+import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
+import org.jooq.Field;
+import org.jooq.Record;
+
+public interface PostgresMailboxMessageFetchStrategy {
+    PostgresMailboxMessageFetchStrategy METADATA = new MetaData();
+    PostgresMailboxMessageFetchStrategy FULL = new Full();
+
+    Field<?>[] fetchFields();
+
+    Function<Record, SimpleMailboxMessage.Builder> toMessageBuilder();
+
+    static Function<Record, SimpleMailboxMessage.Builder> toMessageBuilderMetadata() {
+        return record -> SimpleMailboxMessage.builder()
+            .messageId(PostgresMessageId.Factory.of(record.get(MessageTable.MESSAGE_ID)))
+            .mailboxId(PostgresMailboxId.of(record.get(MAILBOX_ID)))
+            .uid(MessageUid.of(record.get(MESSAGE_UID)))
+            .modseq(ModSeq.of(record.get(MOD_SEQ)))
+            .threadId(RECORD_TO_THREAD_ID_FUNCTION.apply(record))
+            .internalDate(LOCAL_DATE_TIME_DATE_FUNCTION.apply(record.get(PostgresMessageModule.MessageTable.INTERNAL_DATE, LocalDateTime.class)))
+            .saveDate(LOCAL_DATE_TIME_DATE_FUNCTION.apply(record.get(SAVE_DATE, LocalDateTime.class)))
+            .flags(RECORD_TO_FLAGS_FUNCTION.apply(record))
+            .size(record.get(PostgresMessageModule.MessageTable.SIZE))
+            .bodyStartOctet(record.get(BODY_START_OCTET));
+    }
+
+    static Field<?>[] fetchFieldsMetadata() {
+        return new Field[]{
+            tableField(MessageTable.TABLE_NAME, MessageTable.MESSAGE_ID).as(MessageTable.MESSAGE_ID),
+            tableField(MessageTable.TABLE_NAME, MessageTable.INTERNAL_DATE).as(MessageTable.INTERNAL_DATE),
+            tableField(MessageTable.TABLE_NAME, MessageTable.SIZE).as(MessageTable.SIZE),
+            MessageTable.BLOB_ID,
+            MessageTable.MIME_TYPE,
+            MessageTable.MIME_SUBTYPE,
+            MessageTable.BODY_START_OCTET,
+            MessageTable.TEXTUAL_LINE_COUNT,
+            MessageToMailboxTable.MAILBOX_ID,
+            MessageToMailboxTable.MESSAGE_UID,
+            MessageToMailboxTable.MOD_SEQ,
+            MessageToMailboxTable.THREAD_ID,
+            MessageToMailboxTable.IS_DELETED,
+            MessageToMailboxTable.IS_ANSWERED,
+            MessageToMailboxTable.IS_DRAFT,
+            MessageToMailboxTable.IS_FLAGGED,
+            MessageToMailboxTable.IS_RECENT,
+            MessageToMailboxTable.IS_SEEN,
+            MessageToMailboxTable.USER_FLAGS,
+            MessageToMailboxTable.SAVE_DATE};
+    }
+
+    class MetaData implements PostgresMailboxMessageFetchStrategy {
+        public static final Field<?>[] FETCH_FIELDS = fetchFieldsMetadata();
+        public static final Content EMPTY_CONTENT = BYTE_TO_CONTENT_FUNCTION.apply(new byte[0]);
+        public static final PropertyBuilder EMPTY_PROPERTY_BUILDER = new PropertyBuilder();
+
+
+        @Override
+        public Field<?>[] fetchFields() {
+            return FETCH_FIELDS;
+        }
+
+        @Override
+        public Function<Record, SimpleMailboxMessage.Builder> toMessageBuilder() {
+            return record -> toMessageBuilderMetadata()
+                .apply(record)
+                .content(EMPTY_CONTENT)
+                .properties(EMPTY_PROPERTY_BUILDER);
+        }
+    }
+
+    class Full implements PostgresMailboxMessageFetchStrategy {
+
+        public static final Field<?>[] FETCH_FIELDS = ArrayUtils.addAll(fetchFieldsMetadata(),
+            MessageTable.HEADER_CONTENT,
+            MessageTable.TEXTUAL_LINE_COUNT,
+            MessageTable.CONTENT_DESCRIPTION,
+            MessageTable.CONTENT_LOCATION,
+            MessageTable.CONTENT_TRANSFER_ENCODING,
+            MessageTable.CONTENT_DISPOSITION_TYPE,
+            MessageTable.CONTENT_ID,
+            MessageTable.CONTENT_MD5,
+            MessageTable.CONTENT_LANGUAGE,
+            MessageTable.CONTENT_TYPE_PARAMETERS,
+            MessageTable.CONTENT_DISPOSITION_PARAMETERS);
+
+        @Override
+        public Field<?>[] fetchFields() {
+            return FETCH_FIELDS;
+        }
+
+        @Override
+        public Function<Record, SimpleMailboxMessage.Builder> toMessageBuilder() {
+            return record -> toMessageBuilderMetadata()
+                .apply(record)
+                .content(BYTE_TO_CONTENT_FUNCTION.apply(record.get(HEADER_CONTENT)))
+                .properties(RECORD_TO_PROPERTIES_FUNCTION.apply(record));
+        }
+    }
+
+}


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