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/01 09:04:55 UTC

(james-project) branch postgresql updated: JAMES-2586 postgres mailbox annotation dao and mapper (#1822)

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


The following commit(s) were added to refs/heads/postgresql by this push:
     new fb28e7d8e3 JAMES-2586 postgres mailbox annotation dao and mapper (#1822)
fb28e7d8e3 is described below

commit fb28e7d8e3f0b409acd7c6e5186d77c150543a0c
Author: hungphan227 <45...@users.noreply.github.com>
AuthorDate: Fri Dec 1 16:04:49 2023 +0700

    JAMES-2586 postgres mailbox annotation dao and mapper (#1822)
---
 .../postgres/PostgresMailboxAggregateModule.java   |   3 +-
 .../postgres/PostgresMailboxAnnotationModule.java  |  56 ++++++++
 .../postgres/mail/PostgresAnnotationMapper.java    | 140 ++++++++++++++++++++
 .../mail/dao/PostgresMailboxAnnotationDAO.java     | 145 +++++++++++++++++++++
 .../mail/PostgresAnnotationMapperTest.java         |  53 ++++++++
 .../store/mail/model/AnnotationMapperTest.java     |   7 +
 6 files changed, 403 insertions(+), 1 deletion(-)

diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxAggregateModule.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxAggregateModule.java
index 9ec68fd6fd..807adddbd4 100644
--- a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxAggregateModule.java
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxAggregateModule.java
@@ -29,5 +29,6 @@ public interface PostgresMailboxAggregateModule {
     PostgresModule MODULE = PostgresModule.aggregateModules(
         PostgresMailboxModule.MODULE,
         PostgresSubscriptionModule.MODULE,
-        PostgresMessageModule.MODULE);
+        PostgresMessageModule.MODULE,
+        PostgresMailboxAnnotationModule.MODULE);
 }
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxAnnotationModule.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxAnnotationModule.java
new file mode 100644
index 0000000000..4bfae6678b
--- /dev/null
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxAnnotationModule.java
@@ -0,0 +1,56 @@
+/****************************************************************
+ * 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;
+
+import static org.apache.james.mailbox.postgres.mail.PostgresMailboxModule.PostgresMailboxTable;
+
+import java.util.UUID;
+
+import org.apache.james.backends.postgres.PostgresModule;
+import org.apache.james.backends.postgres.PostgresTable;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Table;
+import org.jooq.impl.DSL;
+import org.jooq.impl.DefaultDataType;
+import org.jooq.impl.SQLDataType;
+import org.jooq.postgres.extensions.bindings.HstoreBinding;
+import org.jooq.postgres.extensions.types.Hstore;
+
+public interface PostgresMailboxAnnotationModule {
+    interface PostgresMailboxAnnotationTable {
+        Table<Record> TABLE_NAME = DSL.table("mailbox_annotations");
+
+        Field<UUID> MAILBOX_ID = DSL.field("mailbox_id", SQLDataType.UUID.notNull());
+        Field<Hstore> ANNOTATIONS = DSL.field("annotations", DefaultDataType.getDefaultDataType("hstore").asConvertedDataType(new HstoreBinding()).notNull());
+
+        PostgresTable TABLE = PostgresTable.name(TABLE_NAME.getName())
+            .createTableStep(((dsl, tableName) -> dsl.createTableIfNotExists(tableName)
+                .column(MAILBOX_ID)
+                .column(ANNOTATIONS)
+                .primaryKey(MAILBOX_ID)
+                .constraints(DSL.constraint().foreignKey(MAILBOX_ID).references(PostgresMailboxTable.TABLE_NAME, PostgresMailboxTable.MAILBOX_ID).onDeleteCascade())))
+            .supportsRowLevelSecurity();
+    }
+
+    PostgresModule MODULE = PostgresModule.builder()
+        .addTable(PostgresMailboxAnnotationModule.PostgresMailboxAnnotationTable.TABLE)
+        .build();
+}
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresAnnotationMapper.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresAnnotationMapper.java
new file mode 100644
index 0000000000..867f24fdf4
--- /dev/null
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/PostgresAnnotationMapper.java
@@ -0,0 +1,140 @@
+/****************************************************************
+ * 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;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.model.MailboxAnnotation;
+import org.apache.james.mailbox.model.MailboxAnnotationKey;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.postgres.PostgresMailboxId;
+import org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxAnnotationDAO;
+import org.apache.james.mailbox.store.mail.AnnotationMapper;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class PostgresAnnotationMapper implements AnnotationMapper {
+    private final PostgresMailboxAnnotationDAO annotationDAO;
+
+    @Inject
+    public PostgresAnnotationMapper(PostgresMailboxAnnotationDAO annotationDAO) {
+        this.annotationDAO = annotationDAO;
+    }
+
+    @Override
+    public List<MailboxAnnotation> getAllAnnotations(MailboxId mailboxId) {
+        return getAllAnnotationsReactive(mailboxId)
+            .collectList()
+            .block();
+    }
+
+    @Override
+    public Flux<MailboxAnnotation> getAllAnnotationsReactive(MailboxId mailboxId) {
+        return annotationDAO.getAllAnnotations((PostgresMailboxId) mailboxId);
+    }
+
+    @Override
+    public List<MailboxAnnotation> getAnnotationsByKeys(MailboxId mailboxId, Set<MailboxAnnotationKey> keys) {
+        return getAnnotationsByKeysReactive(mailboxId, keys)
+            .collectList()
+            .block();
+    }
+
+    @Override
+    public Flux<MailboxAnnotation> getAnnotationsByKeysReactive(MailboxId mailboxId, Set<MailboxAnnotationKey> keys) {
+        return annotationDAO.getAnnotationsByKeys((PostgresMailboxId) mailboxId, keys);
+    }
+
+    @Override
+    public List<MailboxAnnotation> getAnnotationsByKeysWithOneDepth(MailboxId mailboxId, Set<MailboxAnnotationKey> keys) {
+        return getAnnotationsByKeysWithOneDepthReactive(mailboxId, keys)
+            .collectList()
+            .block();
+    }
+
+    @Override
+    public Flux<MailboxAnnotation> getAnnotationsByKeysWithOneDepthReactive(MailboxId mailboxId, Set<MailboxAnnotationKey> keys) {
+        return Flux.fromIterable(keys).flatMap(mailboxAnnotationKey ->
+            annotationDAO.getAnnotationsByKeyLike((PostgresMailboxId) mailboxId, mailboxAnnotationKey)
+                .filter(annotation -> mailboxAnnotationKey.isParentOrIsEqual(annotation.getKey())));
+    }
+
+    @Override
+    public List<MailboxAnnotation> getAnnotationsByKeysWithAllDepth(MailboxId mailboxId, Set<MailboxAnnotationKey> keys) {
+        return getAnnotationsByKeysWithAllDepthReactive(mailboxId, keys)
+            .collectList()
+            .block();
+    }
+
+    @Override
+    public Flux<MailboxAnnotation> getAnnotationsByKeysWithAllDepthReactive(MailboxId mailboxId, Set<MailboxAnnotationKey> keys) {
+        return Flux.fromIterable(keys).flatMap(mailboxAnnotationKey ->
+            annotationDAO.getAnnotationsByKeyLike((PostgresMailboxId) mailboxId, mailboxAnnotationKey)
+                .filter(annotation -> mailboxAnnotationKey.isAncestorOrIsEqual(annotation.getKey())));
+    }
+
+    @Override
+    public void deleteAnnotation(MailboxId mailboxId, MailboxAnnotationKey key) {
+        deleteAnnotationReactive(mailboxId, key)
+            .block();
+    }
+
+    @Override
+    public Mono<Void> deleteAnnotationReactive(MailboxId mailboxId, MailboxAnnotationKey key) {
+        return annotationDAO.deleteAnnotation((PostgresMailboxId) mailboxId, key);
+    }
+
+    @Override
+    public void insertAnnotation(MailboxId mailboxId, MailboxAnnotation mailboxAnnotation) {
+        insertAnnotationReactive(mailboxId, mailboxAnnotation)
+            .block();
+    }
+
+    @Override
+    public Mono<Void> insertAnnotationReactive(MailboxId mailboxId, MailboxAnnotation mailboxAnnotation) {
+        return annotationDAO.insertAnnotation((PostgresMailboxId) mailboxId, mailboxAnnotation);
+    }
+
+    @Override
+    public boolean exist(MailboxId mailboxId, MailboxAnnotation mailboxAnnotation) {
+        return existReactive(mailboxId, mailboxAnnotation)
+            .block();
+    }
+
+    @Override
+    public Mono<Boolean> existReactive(MailboxId mailboxId, MailboxAnnotation mailboxAnnotation) {
+        return annotationDAO.exist((PostgresMailboxId) mailboxId, mailboxAnnotation.getKey());
+    }
+
+    @Override
+    public int countAnnotations(MailboxId mailboxId) {
+        return countAnnotationsReactive(mailboxId)
+            .block();
+    }
+
+    @Override
+    public Mono<Integer> countAnnotationsReactive(MailboxId mailboxId) {
+        return annotationDAO.countAnnotations((PostgresMailboxId) mailboxId);
+    }
+}
diff --git a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxAnnotationDAO.java b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxAnnotationDAO.java
new file mode 100644
index 0000000000..845e9cf5e5
--- /dev/null
+++ b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/mail/dao/PostgresMailboxAnnotationDAO.java
@@ -0,0 +1,145 @@
+/****************************************************************
+ * 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.mailbox.postgres.PostgresMailboxAnnotationModule.PostgresMailboxAnnotationTable.ANNOTATIONS;
+import static org.apache.james.mailbox.postgres.PostgresMailboxAnnotationModule.PostgresMailboxAnnotationTable.MAILBOX_ID;
+import static org.apache.james.mailbox.postgres.PostgresMailboxAnnotationModule.PostgresMailboxAnnotationTable.TABLE_NAME;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.james.backends.postgres.utils.PostgresExecutor;
+import org.apache.james.mailbox.model.MailboxAnnotation;
+import org.apache.james.mailbox.model.MailboxAnnotationKey;
+import org.apache.james.mailbox.postgres.PostgresMailboxId;
+import org.jooq.impl.DSL;
+import org.jooq.impl.DefaultDataType;
+import org.jooq.postgres.extensions.types.Hstore;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class PostgresMailboxAnnotationDAO {
+    private static final char SQL_WILDCARD_CHAR = '%';
+    private static final String ANNOTATION_KEY_FIELD_NAME = "annotation_key";
+    private static final String ANNOTATION_VALUE_FIELD_NAME = "annotation_value";
+    private static final String EMPTY_ANNOTATION_VALUE = null;
+
+    private final PostgresExecutor postgresExecutor;
+
+    public PostgresMailboxAnnotationDAO(PostgresExecutor postgresExecutor) {
+        this.postgresExecutor = postgresExecutor;
+    }
+
+    public Flux<MailboxAnnotation> getAllAnnotations(PostgresMailboxId mailboxId) {
+        return postgresExecutor.executeRows(dslContext ->
+                Flux.from(dslContext.selectFrom(TABLE_NAME)
+                    .where(MAILBOX_ID.eq(mailboxId.asUuid()))))
+            .singleOrEmpty()
+            .map(record -> record.get(ANNOTATIONS, LinkedHashMap.class))
+            .flatMapIterable(this::hstoreToAnnotations);
+    }
+
+    public Flux<MailboxAnnotation> getAnnotationsByKeys(PostgresMailboxId mailboxId, Set<MailboxAnnotationKey> keys) {
+        return postgresExecutor.executeRows(dslContext ->
+                Flux.from(dslContext.select(DSL.function("slice",
+                        DefaultDataType.getDefaultDataType("hstore"),
+                        ANNOTATIONS,
+                        DSL.array(keys.stream().map(mailboxAnnotationKey -> DSL.val(mailboxAnnotationKey.asString())).collect(Collectors.toUnmodifiableList()))))
+                    .from(TABLE_NAME)
+                    .where(MAILBOX_ID.eq(mailboxId.asUuid()))))
+            .singleOrEmpty()
+            .map(record -> record.get(0, LinkedHashMap.class))
+            .flatMapIterable(this::hstoreToAnnotations);
+    }
+
+    public Mono<Boolean> exist(PostgresMailboxId mailboxId, MailboxAnnotationKey key) {
+        return postgresExecutor.executeRows(dslContext ->
+                Flux.from(dslContext.select(DSL.field(" exist(" + ANNOTATIONS.getName() + ",?)", key.asString()))
+                    .from(TABLE_NAME)
+                    .where(MAILBOX_ID.eq(mailboxId.asUuid()))))
+            .singleOrEmpty()
+            .map(record -> record.get(0, Boolean.class))
+            .defaultIfEmpty(false);
+    }
+
+    public Flux<MailboxAnnotation> getAnnotationsByKeyLike(PostgresMailboxId mailboxId, MailboxAnnotationKey key) {
+        return postgresExecutor.executeRows(dslContext ->
+                Flux.from(dslContext.selectFrom(
+                    dslContext.select(DSL.field("(each(annotations)).key").as(ANNOTATION_KEY_FIELD_NAME),
+                            DSL.field("(each(annotations)).value").as(ANNOTATION_VALUE_FIELD_NAME))
+                        .from(TABLE_NAME)
+                        .where(MAILBOX_ID.eq(mailboxId.asUuid())).asTable())
+                    .where(DSL.field(ANNOTATION_KEY_FIELD_NAME).like(key.asString() + SQL_WILDCARD_CHAR))))
+            .map(record -> MailboxAnnotation.newInstance(new MailboxAnnotationKey(record.get(ANNOTATION_KEY_FIELD_NAME, String.class)),
+                record.get(ANNOTATION_VALUE_FIELD_NAME, String.class)));
+    }
+
+    public Mono<Void> insertAnnotation(PostgresMailboxId mailboxId, MailboxAnnotation mailboxAnnotation) {
+        Preconditions.checkArgument(!mailboxAnnotation.isNil());
+
+        return postgresExecutor.executeVoid(dslContext ->
+            Mono.from(dslContext.insertInto(TABLE_NAME, MAILBOX_ID, ANNOTATIONS)
+                .values(mailboxId.asUuid(), annotationAsHstore(mailboxAnnotation))
+                .onConflict(MAILBOX_ID)
+                .doUpdate()
+                .set(DSL.field(ANNOTATIONS.getName() + "[?]",
+                    mailboxAnnotation.getKey().asString()),
+                    mailboxAnnotation.getValue().orElse(EMPTY_ANNOTATION_VALUE))));
+    }
+
+    public Mono<Void> deleteAnnotation(PostgresMailboxId mailboxId, MailboxAnnotationKey key) {
+        return postgresExecutor.executeVoid(dslContext ->
+            Mono.from(dslContext.update(TABLE_NAME)
+                .set(DSL.field(ANNOTATIONS.getName()),
+                    (Object) DSL.function("delete",
+                        DefaultDataType.getDefaultDataType("hstore"),
+                        ANNOTATIONS,
+                        DSL.val(key.asString())))
+                .where(MAILBOX_ID.eq(mailboxId.asUuid()))));
+    }
+
+    public Mono<Integer> countAnnotations(PostgresMailboxId mailboxId) {
+        return postgresExecutor.executeRows(dslContext ->
+                Flux.from(dslContext.select(DSL.field("array_length(akeys(" + ANNOTATIONS.getName() + "), 1)"))
+                    .from(TABLE_NAME)
+                    .where(MAILBOX_ID.eq(mailboxId.asUuid()))))
+            .singleOrEmpty()
+            .map(record -> record.get(0, Integer.class))
+            .defaultIfEmpty(0);
+    }
+
+    private List<MailboxAnnotation> hstoreToAnnotations(LinkedHashMap<String, String> hstore) {
+        return hstore.entrySet()
+            .stream()
+            .map(entry -> MailboxAnnotation.newInstance(new MailboxAnnotationKey(entry.getKey()), entry.getValue()))
+            .collect(Collectors.toList());
+    }
+
+    private Hstore annotationAsHstore(MailboxAnnotation mailboxAnnotation) {
+        return Hstore.hstore(ImmutableMap.of(mailboxAnnotation.getKey().asString(), mailboxAnnotation.getValue().get()));
+    }
+}
diff --git a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/mail/PostgresAnnotationMapperTest.java b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/mail/PostgresAnnotationMapperTest.java
new file mode 100644
index 0000000000..0b2d75ba29
--- /dev/null
+++ b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/mail/PostgresAnnotationMapperTest.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * 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;
+
+import org.apache.james.backends.postgres.PostgresExtension;
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.UidValidity;
+import org.apache.james.mailbox.postgres.PostgresMailboxAggregateModule;
+import org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxAnnotationDAO;
+import org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxDAO;
+import org.apache.james.mailbox.store.mail.AnnotationMapper;
+import org.apache.james.mailbox.store.mail.MailboxMapper;
+import org.apache.james.mailbox.store.mail.model.AnnotationMapperTest;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class PostgresAnnotationMapperTest extends AnnotationMapperTest {
+    private static final UidValidity UID_VALIDITY = UidValidity.of(42);
+    private static final Username BENWA = Username.of("benwa");
+    protected static final MailboxPath benwaInboxPath = MailboxPath.forUser(BENWA, "INBOX");
+
+    @RegisterExtension
+    static PostgresExtension postgresExtension = PostgresExtension.withoutRowLevelSecurity(PostgresMailboxAggregateModule.MODULE);
+
+    @Override
+    protected AnnotationMapper createAnnotationMapper() {
+        return new PostgresAnnotationMapper(new PostgresMailboxAnnotationDAO(postgresExtension.getPostgresExecutor()));
+    }
+
+    @Override
+    protected MailboxId generateMailboxId() {
+        MailboxMapper mailboxMapper = new PostgresMailboxMapper(new PostgresMailboxDAO(postgresExtension.getPostgresExecutor()));
+        return mailboxMapper.create(benwaInboxPath, UID_VALIDITY).block().getMailboxId();
+    }
+}
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AnnotationMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AnnotationMapperTest.java
index c00d6b2639..974edd0fc9 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AnnotationMapperTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AnnotationMapperTest.java
@@ -204,6 +204,13 @@ public abstract class AnnotationMapperTest {
         assertThat(annotationMapper.exist(mailboxId, PRIVATE_ANNOTATION)).isFalse();
     }
 
+    @Test
+    void isExistedShouldReturnFalseIfMailboxIdExistAndAnnotationIsNotStored() {
+        annotationMapper.insertAnnotation(mailboxId, PRIVATE_ANNOTATION);
+
+        assertThat(annotationMapper.exist(mailboxId, PRIVATE_USER_ANNOTATION)).isFalse();
+    }
+
     @Test
     void countAnnotationShouldReturnZeroIfNoMoreAnnotationBelongToMailbox() {
         assertThat(annotationMapper.countAnnotations(mailboxId)).isEqualTo(0);


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