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 31d8ec6e77 JAMES-2586 Postgres Subscription mapper (#1775)
31d8ec6e77 is described below

commit 31d8ec6e7759ba487269eb3592f7f8dbfeb68c7a
Author: vttran <[email protected]>
AuthorDate: Wed Nov 8 09:56:20 2023 +0700

    JAMES-2586 Postgres Subscription mapper (#1775)
---
 backends-common/postgres/pom.xml                   |  1 -
 .../james/backends/postgres/PostgresTable.java     | 10 ++--
 .../backends/postgres/utils/PostgresExecutor.java  | 15 +++++
 .../james/backends/postgres/PostgresExtension.java |  4 ++
 .../postgres/PostgresTableManagerTest.java         |  2 +-
 mailbox/postgres/pom.xml                           | 11 ++++
 .../mailbox/jpa/user/PostgresSubscriptionDAO.java  | 57 ++++++++++++++++++
 .../jpa/user/PostgresSubscriptionMapper.java       | 70 ++++++++++++++++++++++
 .../jpa/user/PostgresSubscriptionModule.java       | 55 +++++++----------
 .../jpa/user/PostgresSubscriptionTable.java        | 42 +++----------
 .../jpa/user/PostgresSubscriptionMapperTest.java   | 45 ++++----------
 pom.xml                                            |  5 ++
 12 files changed, 210 insertions(+), 107 deletions(-)

diff --git a/backends-common/postgres/pom.xml b/backends-common/postgres/pom.xml
index 3cf5b72327..b9d8923063 100644
--- a/backends-common/postgres/pom.xml
+++ b/backends-common/postgres/pom.xml
@@ -82,7 +82,6 @@
         <dependency>
             <groupId>org.testcontainers</groupId>
             <artifactId>postgresql</artifactId>
-            <version>1.19.1</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTable.java
 
b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTable.java
index 331f530ad7..1956d3c5e8 100644
--- 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTable.java
+++ 
b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/PostgresTable.java
@@ -41,21 +41,21 @@ public class PostgresTable {
 
     @FunctionalInterface
     public interface RequireRowLevelSecurity {
-        PostgresTable enableRLS(boolean enableRowLevelSecurity);
+        PostgresTable enableRowLevelSecurity(boolean enableRowLevelSecurity);
 
         default PostgresTable noRLS() {
-            return enableRLS(false);
+            return enableRowLevelSecurity(false);
         }
 
-        default PostgresTable enableRLS() {
-            return enableRLS(true);
+        default PostgresTable enableRowLevelSecurity() {
+            return enableRowLevelSecurity(true);
         }
     }
 
     public static RequireCreateTableStep name(String tableName) {
         Preconditions.checkNotNull(tableName);
 
-        return createTableFunction -> enableRLS -> new 
PostgresTable(tableName, enableRLS, dsl -> createTableFunction.createTable(dsl, 
tableName));
+        return createTableFunction -> enableRowLevelSecurity -> new 
PostgresTable(tableName, enableRowLevelSecurity, dsl -> 
createTableFunction.createTable(dsl, tableName));
     }
 
     private final String name;
diff --git 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
 
b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
index 78636dc186..43b5efa4e1 100644
--- 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
+++ 
b/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
@@ -19,9 +19,12 @@
 
 package org.apache.james.backends.postgres.utils;
 
+import java.util.function.Function;
+
 import javax.inject.Inject;
 
 import org.jooq.DSLContext;
+import org.jooq.Record;
 import org.jooq.SQLDialect;
 import org.jooq.conf.Settings;
 import org.jooq.impl.DSL;
@@ -29,6 +32,7 @@ import org.jooq.impl.DSL;
 import com.google.common.annotations.VisibleForTesting;
 
 import io.r2dbc.spi.Connection;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class PostgresExecutor {
@@ -47,6 +51,17 @@ public class PostgresExecutor {
         return connection.map(con -> DSL.using(con, PGSQL_DIALECT, SETTINGS));
     }
 
+    public Mono<Void> executeVoid(Function<DSLContext, Mono<?>> queryFunction) 
{
+        return dslContext()
+            .flatMap(queryFunction)
+            .then();
+    }
+
+    public Flux<Record> executeRows(Function<DSLContext, Flux<Record>> 
queryFunction) {
+        return dslContext()
+            .flatMapMany(queryFunction);
+    }
+
     public Mono<Connection> connection() {
         return connection;
     }
diff --git 
a/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java
 
b/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java
index 0e4ab28fa3..35606c4f8e 100644
--- 
a/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java
+++ 
b/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresExtension.java
@@ -102,6 +102,10 @@ public class PostgresExtension implements 
GuiceModuleTestExtension {
         return postgresExecutor.connection();
     }
 
+    public PostgresExecutor getPostgresExecutor() {
+        return postgresExecutor;
+    }
+
     private void initTablesAndIndexes() {
         PostgresTableManager postgresTableManager = new 
PostgresTableManager(postgresExecutor, postgresModule);
         postgresTableManager.initializeTables().block();
diff --git 
a/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresTableManagerTest.java
 
b/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresTableManagerTest.java
index 007ff246a5..c08a070a48 100644
--- 
a/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresTableManagerTest.java
+++ 
b/backends-common/postgres/src/test/java/org/apache/james/backends/postgres/PostgresTableManagerTest.java
@@ -286,7 +286,7 @@ class PostgresTableManagerTest {
             .createTableStep((dsl, tbn) -> dsl.createTable(tbn)
                 .column("clm1", SQLDataType.UUID.notNull())
                 .column("clm2", SQLDataType.VARCHAR(255).notNull()))
-            .enableRLS();
+            .enableRowLevelSecurity();
 
         PostgresModule module = PostgresModule.table(table);
 
diff --git a/mailbox/postgres/pom.xml b/mailbox/postgres/pom.xml
index d63b431281..690389fab5 100644
--- a/mailbox/postgres/pom.xml
+++ b/mailbox/postgres/pom.xml
@@ -99,6 +99,12 @@
             <artifactId>james-server-data-jpa</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-guice-common</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-testing</artifactId>
@@ -140,6 +146,11 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionDAO.java
 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionDAO.java
new file mode 100644
index 0000000000..a1a903e90d
--- /dev/null
+++ 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionDAO.java
@@ -0,0 +1,57 @@
+/****************************************************************
+ * 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.jpa.user;
+
+import static 
org.apache.james.mailbox.jpa.user.PostgresSubscriptionTable.MAILBOX;
+import static 
org.apache.james.mailbox.jpa.user.PostgresSubscriptionTable.TABLE_NAME;
+import static org.apache.james.mailbox.jpa.user.PostgresSubscriptionTable.USER;
+
+import org.apache.james.backends.postgres.utils.PostgresExecutor;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class PostgresSubscriptionDAO {
+    protected final PostgresExecutor executor;
+
+    public PostgresSubscriptionDAO(PostgresExecutor executor) {
+        this.executor = executor;
+    }
+
+    public Mono<Void> save(String username, String mailbox) {
+        return executor.executeVoid(dsl -> 
Mono.from(dsl.insertInto(TABLE_NAME, USER, MAILBOX)
+            .values(username, mailbox)
+            .onConflict(USER, MAILBOX)
+            .doNothing()
+            .returningResult(MAILBOX)));
+    }
+
+    public Mono<Void> delete(String username, String mailbox) {
+        return executor.executeVoid(dsl -> Mono.from(dsl.deleteFrom(TABLE_NAME)
+            .where(USER.eq(username))
+            .and(MAILBOX.eq(mailbox))));
+    }
+
+    public Flux<String> findMailboxByUser(String username) {
+        return executor.executeRows(dsl -> Flux.from(dsl.selectFrom(TABLE_NAME)
+                .where(USER.eq(username))))
+            .map(record -> record.get(MAILBOX));
+    }
+}
diff --git 
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionMapper.java
 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionMapper.java
new file mode 100644
index 0000000000..02514fef6a
--- /dev/null
+++ 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionMapper.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * 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.jpa.user;
+
+import java.util.List;
+
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.exception.SubscriptionException;
+import org.apache.james.mailbox.store.user.SubscriptionMapper;
+import org.apache.james.mailbox.store.user.model.Subscription;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class PostgresSubscriptionMapper implements SubscriptionMapper {
+
+    private final PostgresSubscriptionDAO subscriptionDAO;
+
+    public PostgresSubscriptionMapper(PostgresSubscriptionDAO subscriptionDAO) 
{
+        this.subscriptionDAO = subscriptionDAO;
+    }
+
+    @Override
+    public void save(Subscription subscription) throws SubscriptionException {
+        saveReactive(subscription).block();
+    }
+
+    @Override
+    public List<Subscription> findSubscriptionsForUser(Username user) throws 
SubscriptionException {
+        return findSubscriptionsForUserReactive(user).collectList().block();
+    }
+
+    @Override
+    public void delete(Subscription subscription) throws SubscriptionException 
{
+        deleteReactive(subscription).block();
+    }
+
+    @Override
+    public Mono<Void> saveReactive(Subscription subscription) {
+        return subscriptionDAO.save(subscription.getUser().asString(), 
subscription.getMailbox());
+    }
+
+    @Override
+    public Flux<Subscription> findSubscriptionsForUserReactive(Username user) {
+        return subscriptionDAO.findMailboxByUser(user.asString())
+            .map(mailbox -> new Subscription(user, mailbox));
+    }
+
+    @Override
+    public Mono<Void> deleteReactive(Subscription subscription) {
+        return subscriptionDAO.delete(subscription.getUser().asString(), 
subscription.getMailbox());
+    }
+}
diff --git 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionModule.java
similarity index 52%
copy from 
backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
copy to 
mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionModule.java
index 78636dc186..66d5372eeb 100644
--- 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
+++ 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionModule.java
@@ -17,42 +17,29 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.backends.postgres.utils;
+package org.apache.james.mailbox.jpa.user;
 
-import javax.inject.Inject;
+import static 
org.apache.james.mailbox.jpa.user.PostgresSubscriptionTable.MAILBOX;
+import static 
org.apache.james.mailbox.jpa.user.PostgresSubscriptionTable.TABLE_NAME;
+import static org.apache.james.mailbox.jpa.user.PostgresSubscriptionTable.USER;
 
-import org.jooq.DSLContext;
-import org.jooq.SQLDialect;
-import org.jooq.conf.Settings;
+import org.apache.james.backends.postgres.PostgresIndex;
+import org.apache.james.backends.postgres.PostgresModule;
+import org.apache.james.backends.postgres.PostgresTable;
 import org.jooq.impl.DSL;
 
-import com.google.common.annotations.VisibleForTesting;
-
-import io.r2dbc.spi.Connection;
-import reactor.core.publisher.Mono;
-
-public class PostgresExecutor {
-
-    private static final SQLDialect PGSQL_DIALECT = SQLDialect.POSTGRES;
-    private static final Settings SETTINGS = new Settings()
-        .withRenderFormatted(true);
-    private final Mono<Connection> connection;
-
-    @Inject
-    public PostgresExecutor(Mono<Connection> connection) {
-        this.connection = connection;
-    }
-
-    public Mono<DSLContext> dslContext() {
-        return connection.map(con -> DSL.using(con, PGSQL_DIALECT, SETTINGS));
-    }
-
-    public Mono<Connection> connection() {
-        return connection;
-    }
-
-    @VisibleForTesting
-    public Mono<Void> dispose() {
-        return connection.flatMap(con -> Mono.from(con.close()));
-    }
+public interface PostgresSubscriptionModule {
+    PostgresTable TABLE = PostgresTable.name(TABLE_NAME.getName())
+        .createTableStep(((dsl, tableName) -> dsl.createTable(tableName)
+            .column(MAILBOX)
+            .column(USER)
+            .constraint(DSL.unique(MAILBOX, USER))))
+        .enableRowLevelSecurity();
+    PostgresIndex INDEX = PostgresIndex.name("subscription_user_index")
+        .createIndexStep((dsl, indexName) -> dsl.createIndex(indexName)
+            .on(TABLE_NAME, USER));
+    PostgresModule MODULE = PostgresModule.builder()
+        .addTable(TABLE)
+        .addIndex(INDEX)
+        .build();
 }
diff --git 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionTable.java
similarity index 55%
copy from 
backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
copy to 
mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionTable.java
index 78636dc186..3cdc2cf1e8 100644
--- 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
+++ 
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionTable.java
@@ -17,42 +17,18 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.backends.postgres.utils;
+package org.apache.james.mailbox.jpa.user;
 
-import javax.inject.Inject;
-
-import org.jooq.DSLContext;
-import org.jooq.SQLDialect;
-import org.jooq.conf.Settings;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Table;
 import org.jooq.impl.DSL;
+import org.jooq.impl.SQLDataType;
 
-import com.google.common.annotations.VisibleForTesting;
-
-import io.r2dbc.spi.Connection;
-import reactor.core.publisher.Mono;
-
-public class PostgresExecutor {
-
-    private static final SQLDialect PGSQL_DIALECT = SQLDialect.POSTGRES;
-    private static final Settings SETTINGS = new Settings()
-        .withRenderFormatted(true);
-    private final Mono<Connection> connection;
-
-    @Inject
-    public PostgresExecutor(Mono<Connection> connection) {
-        this.connection = connection;
-    }
-
-    public Mono<DSLContext> dslContext() {
-        return connection.map(con -> DSL.using(con, PGSQL_DIALECT, SETTINGS));
-    }
+public interface PostgresSubscriptionTable {
 
-    public Mono<Connection> connection() {
-        return connection;
-    }
+    Field<String> MAILBOX = DSL.field("mailbox", 
SQLDataType.VARCHAR(255).notNull());
+    Field<String> USER = DSL.field("user_name", 
SQLDataType.VARCHAR(255).notNull());
+    Table<Record> TABLE_NAME = DSL.table("subscription");
 
-    @VisibleForTesting
-    public Mono<Void> dispose() {
-        return connection.flatMap(con -> Mono.from(con.close()));
-    }
 }
diff --git 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionMapperTest.java
similarity index 54%
copy from 
backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
copy to 
mailbox/postgres/src/test/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionMapperTest.java
index 78636dc186..009a900c35 100644
--- 
a/backends-common/postgres/src/main/java/org/apache/james/backends/postgres/utils/PostgresExecutor.java
+++ 
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/jpa/user/PostgresSubscriptionMapperTest.java
@@ -17,42 +17,21 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.backends.postgres.utils;
+package org.apache.james.mailbox.jpa.user;
 
-import javax.inject.Inject;
+import org.apache.james.backends.postgres.PostgresExtension;
+import org.apache.james.mailbox.store.user.SubscriptionMapper;
+import org.apache.james.mailbox.store.user.SubscriptionMapperTest;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import org.jooq.DSLContext;
-import org.jooq.SQLDialect;
-import org.jooq.conf.Settings;
-import org.jooq.impl.DSL;
+public class PostgresSubscriptionMapperTest extends SubscriptionMapperTest {
 
-import com.google.common.annotations.VisibleForTesting;
+    @RegisterExtension
+    static PostgresExtension postgresExtension = new 
PostgresExtension(PostgresSubscriptionModule.MODULE);
 
-import io.r2dbc.spi.Connection;
-import reactor.core.publisher.Mono;
-
-public class PostgresExecutor {
-
-    private static final SQLDialect PGSQL_DIALECT = SQLDialect.POSTGRES;
-    private static final Settings SETTINGS = new Settings()
-        .withRenderFormatted(true);
-    private final Mono<Connection> connection;
-
-    @Inject
-    public PostgresExecutor(Mono<Connection> connection) {
-        this.connection = connection;
-    }
-
-    public Mono<DSLContext> dslContext() {
-        return connection.map(con -> DSL.using(con, PGSQL_DIALECT, SETTINGS));
-    }
-
-    public Mono<Connection> connection() {
-        return connection;
-    }
-
-    @VisibleForTesting
-    public Mono<Void> dispose() {
-        return connection.flatMap(con -> Mono.from(con.close()));
+    @Override
+    protected SubscriptionMapper createSubscriptionMapper() {
+        PostgresSubscriptionDAO dao = new 
PostgresSubscriptionDAO(postgresExtension.getPostgresExecutor());
+        return new PostgresSubscriptionMapper(dao);
     }
 }
diff --git a/pom.xml b/pom.xml
index f2de37f723..cec1d1216c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2956,6 +2956,11 @@
                 <artifactId>junit-jupiter</artifactId>
                 <version>${testcontainers.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.testcontainers</groupId>
+                <artifactId>postgresql</artifactId>
+                <version>1.19.1</version>
+            </dependency>
             <dependency>
                 <groupId>org.testcontainers</groupId>
                 <artifactId>pulsar</artifactId>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to