Skip to content

Commit

Permalink
Merge pull request #10433 from DavideD/10432-session-producer
Browse files Browse the repository at this point in the history
[#10432] Allow injection of a reactive session not wrapped in a Mutiny/CompletionStage
  • Loading branch information
Sanne authored Jul 3, 2020
2 parents e118d5e + 0086944 commit 5b5f845
Show file tree
Hide file tree
Showing 10 changed files with 608 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,29 @@ public void disposeMutinySession(@Disposes Uni<Mutiny.Session> reactiveSession)
reactiveSession.subscribe().with(Mutiny.Session::close);
}

@Produces
@RequestScoped
@DefaultBean
public Stage.Session createStageSession() {
return reactiveSessionFactory.createSession();
}

@Produces
@RequestScoped
@DefaultBean
public Mutiny.Session createMutinySession() {
return mutinySessionFactory.createSession();
}

public void disposeStageSession(@Disposes Stage.Session reactiveSession) {
if (reactiveSession != null) {
reactiveSession.close();
}
}

public void disposeMutinySession(@Disposes Mutiny.Session reactiveSession) {
if (reactiveSession != null) {
reactiveSession.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package io.quarkus.it.hibernate.reactive.db2;

import java.util.concurrent.CompletionStage;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.hibernate.reactive.mutiny.Mutiny;
import org.hibernate.reactive.stage.Stage;

import io.smallrye.mutiny.Uni;
import io.vertx.mutiny.db2client.DB2Pool;
import io.vertx.mutiny.sqlclient.Row;
import io.vertx.mutiny.sqlclient.RowSet;
import io.vertx.mutiny.sqlclient.Tuple;

@Path("/alternative-tests")
@Produces(MediaType.APPLICATION_JSON)
public class HibernateReactiveDB2AlternativeTestEndpoint {

@Inject
Stage.Session stageSession;

@Inject
Mutiny.Session mutinySession;

// Injecting a Vert.x Pool is not required, it us only used to
// independently validate the contents of the database for the test
@Inject
DB2Pool db2Pool;

@GET
@Path("/reactiveFind")
public CompletionStage<GuineaPig> reactiveFind() {
final GuineaPig expectedPig = new GuineaPig(5, "Aloi");
return populateDB().convert().toCompletionStage()
.thenCompose(junk -> stageSession.find(GuineaPig.class, expectedPig.getId()));
}

@GET
@Path("/reactiveFindMutiny")
public Uni<GuineaPig> reactiveFindMutiny() {
final GuineaPig expectedPig = new GuineaPig(5, "Aloi");
return populateDB()
.onItem().produceUni(junk -> mutinySession.find(GuineaPig.class, expectedPig.getId()));
}

@GET
@Path("/reactivePersist")
public Uni<String> reactivePersist() {
return mutinySession.persist(new GuineaPig(10, "Tulip"))
.onItem().produceUni(s -> s.flush())
.onItem().produceUni(junk -> selectNameFromId(10));
}

@GET
@Path("/reactiveRemoveTransientEntity")
public Uni<String> reactiveRemoveTransientEntity() {
return populateDB()
.onItem().produceUni(junk -> selectNameFromId(5))
.onItem().apply(name -> {
if (name == null) {
throw new AssertionError("Database was not populated properly");
}
return name;
})
.onItem().produceUni(junk -> mutinySession.merge(new GuineaPig(5, "Aloi")))
.onItem().produceUni(aloi -> mutinySession.remove(aloi))
.onItem().produceUni(junk -> mutinySession.flush())
.onItem().produceUni(junk -> selectNameFromId(5))
.onItem().ifNotNull().apply(result -> result)
.onItem().ifNull().continueWith("OK");
}

@GET
@Path("/reactiveRemoveManagedEntity")
public Uni<String> reactiveRemoveManagedEntity() {
return populateDB()
.onItem().produceUni(junk -> mutinySession.find(GuineaPig.class, 5))
.onItem().produceUni(aloi -> mutinySession.remove(aloi))
.onItem().produceUni(junk -> mutinySession.flush())
.onItem().produceUni(junk -> selectNameFromId(5))
.onItem().ifNotNull().apply(result -> result)
.onItem().ifNull().continueWith("OK");
}

@GET
@Path("/reactiveUpdate")
public Uni<String> reactiveUpdate() {
final String NEW_NAME = "Tina";
return populateDB()
.onItem().produceUni(junk -> mutinySession.find(GuineaPig.class, 5))
.onItem().apply(pig -> {
if (NEW_NAME.equals(pig.getName())) {
throw new AssertionError("Pig already had name " + NEW_NAME);
}
pig.setName(NEW_NAME);
return pig;
})
.onItem().produceUni(junk -> mutinySession.flush())
.onItem().produceUni(junk -> selectNameFromId(5));
}

private Uni<RowSet<Row>> populateDB() {
return db2Pool.query("DELETE FROM Pig").execute()
.flatMap(junk -> db2Pool.preparedQuery("INSERT INTO Pig (id, name) VALUES (5, 'Aloi')").execute());
}

private Uni<String> selectNameFromId(Integer id) {
return db2Pool.preparedQuery("SELECT name FROM Pig WHERE id = ?").execute(Tuple.of(id)).map(rowSet -> {
if (rowSet.size() == 1) {
return rowSet.iterator().next().getString(0);
} else if (rowSet.size() > 1) {
throw new AssertionError("More than one result returned: " + rowSet.size());
} else {
return null; // Size 0
}
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.it.hibernate.reactive.db2;

import io.quarkus.test.junit.NativeImageTest;

@NativeImageTest
public class HibernateReactiveDB2AlternativeInGraalIT extends HibernateReactiveDB2AlternativeTest {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.quarkus.it.hibernate.reactive.db2;

import static org.hamcrest.Matchers.is;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;

/**
* Test various JPA operations running in Quarkus when the session is injected without Uni or CompletionStage.
*/
@QuarkusTest
public class HibernateReactiveDB2AlternativeTest {

@Test
public void reactiveFind() {
RestAssured.when()
.get("/alternative-tests/reactiveFind")
.then()
.body(is("{\"id\":5,\"name\":\"Aloi\"}"));
}

@Test
public void reactiveFindMutiny() {
RestAssured.when()
.get("/alternative-tests/reactiveFindMutiny")
.then()
.body(is("{\"id\":5,\"name\":\"Aloi\"}"));
}

@Test
public void reactivePersist() {
RestAssured.when()
.get("/alternative-tests/reactivePersist")
.then()
.body(is("Tulip"));
}

@Test
public void reactiveRemoveTransientEntity() {
RestAssured.when()
.get("/alternative-tests/reactiveRemoveTransientEntity")
.then()
.body(is("OK"));
}

@Test
public void reactiveRemoveManagedEntity() {
RestAssured.when()
.get("/alternative-tests/reactiveRemoveManagedEntity")
.then()
.body(is("OK"));
}

@Test
public void reactiveUpdate() {
RestAssured.when()
.get("/alternative-tests/reactiveUpdate")
.then()
.body(is("Tina"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package io.quarkus.it.hibernate.reactive.mysql;

import java.util.concurrent.CompletionStage;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.hibernate.reactive.mutiny.Mutiny;
import org.hibernate.reactive.stage.Stage;

import io.smallrye.mutiny.Uni;
import io.vertx.mutiny.mysqlclient.MySQLPool;
import io.vertx.mutiny.sqlclient.Row;
import io.vertx.mutiny.sqlclient.RowSet;
import io.vertx.mutiny.sqlclient.Tuple;

@Path("/alternative-tests")
@Produces(MediaType.APPLICATION_JSON)
public class HibernateReactiveMySQLAlternativeTestEndpoint {

@Inject
Stage.Session stageSession;

@Inject
Mutiny.Session mutinySession;

// Injecting a Vert.x Pool is not required, it us only used to
// independently validate the contents of the database for the test
@Inject
MySQLPool mysqlPool;

@GET
@Path("/reactiveFind")
public CompletionStage<GuineaPig> reactiveFind() {
final GuineaPig expectedPig = new GuineaPig(5, "Aloi");
return populateDB().convert().toCompletionStage()
.thenCompose(junk -> stageSession.find(GuineaPig.class, expectedPig.getId()));
}

@GET
@Path("/reactiveFindMutiny")
public Uni<GuineaPig> reactiveFindMutiny() {
final GuineaPig expectedPig = new GuineaPig(5, "Aloi");
return populateDB()
.onItem().produceUni(junk -> mutinySession.find(GuineaPig.class, expectedPig.getId()));
}

@GET
@Path("/reactivePersist")
@Produces(MediaType.APPLICATION_JSON)
public Uni<String> reactivePersist() {
return mutinySession.persist(new GuineaPig(10, "Tulip"))
.onItem().produceUni(s -> s.flush())
.onItem().produceUni(junk -> selectNameFromId(10));
}

@GET
@Path("/reactiveRemoveTransientEntity")
public Uni<String> reactiveRemoveTransientEntity() {
return populateDB()
.onItem().produceUni(junk -> selectNameFromId(5))
.onItem().apply(name -> {
if (name == null) {
throw new AssertionError("Database was not populated properly");
}
return name;
})
.onItem().produceUni(junk -> mutinySession.merge(new GuineaPig(5, "Aloi")))
.onItem().produceUni(aloi -> mutinySession.remove(aloi))
.onItem().produceUni(junk -> mutinySession.flush())
.onItem().produceUni(junk -> selectNameFromId(5))
.onItem().ifNotNull().apply(result -> result)
.onItem().ifNull().continueWith("OK");
}

@GET
@Path("/reactiveRemoveManagedEntity")
public Uni<String> reactiveRemoveManagedEntity() {
return populateDB()
.onItem().produceUni(junk -> mutinySession.find(GuineaPig.class, 5))
.onItem().produceUni(aloi -> mutinySession.remove(aloi))
.onItem().produceUni(junk -> mutinySession.flush())
.onItem().produceUni(junk -> selectNameFromId(5))
.onItem().ifNotNull().apply(result -> result)
.onItem().ifNull().continueWith("OK");
}

@GET
@Path("/reactiveUpdate")
public Uni<String> reactiveUpdate() {
final String NEW_NAME = "Tina";
return populateDB()
.onItem().produceUni(junk -> mutinySession.find(GuineaPig.class, 5))
.onItem().apply(pig -> {
if (NEW_NAME.equals(pig.getName())) {
throw new AssertionError("Pig already had name " + NEW_NAME);
}
pig.setName(NEW_NAME);
return pig;
})
.onItem().produceUni(junk -> mutinySession.flush())
.onItem().produceUni(junk -> selectNameFromId(5));
}

private Uni<RowSet<Row>> populateDB() {
return mysqlPool.query("DELETE FROM Pig").execute()
.flatMap(junk -> mysqlPool.preparedQuery("INSERT INTO Pig (id, name) VALUES (5, 'Aloi')").execute());
}

private Uni<String> selectNameFromId(Integer id) {
return mysqlPool.preparedQuery("SELECT name FROM Pig WHERE id = ?").execute(Tuple.of(id)).map(rowSet -> {
if (rowSet.size() == 1) {
return rowSet.iterator().next().getString(0);
} else if (rowSet.size() > 1) {
throw new AssertionError("More than one result returned: " + rowSet.size());
} else {
return null; // Size 0
}
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.it.hibernate.reactive.mysql;

import io.quarkus.test.junit.NativeImageTest;

@NativeImageTest
public class HibernateReactiveMySQLAlternativeInGraalIT extends HibernateReactiveMySQLAlternativeTest {
}
Loading

0 comments on commit 5b5f845

Please sign in to comment.