diff --git a/README.md b/README.md index fa213c2de..8e459aeb9 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with: - CockroachDB 22.1 - MS SQL Server 2019 - Oracle 21.3 -- [Hibernate ORM][] 6.2.4.Final +- [Hibernate ORM][] 6.2.5.Final - [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.4.3 - [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.4.3 - [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.4.3 diff --git a/build.gradle b/build.gradle index 1ad183c3a..008745feb 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { id 'java-library' id 'maven-publish' id 'com.diffplug.spotless' version '6.18.0' - id 'nu.studer.credentials' version '2.1' + id 'nu.studer.credentials' version '2.2' id 'org.asciidoctor.jvm.convert' version '3.3.2' apply false id 'io.github.gradle-nexus.publish-plugin' version '1.3.0' } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveFlushEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveFlushEventListener.java index d850ce3e2..97043ed02 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveFlushEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveFlushEventListener.java @@ -13,9 +13,12 @@ import org.hibernate.event.spi.FlushEvent; import org.hibernate.event.spi.FlushEventListener; import org.hibernate.reactive.event.ReactiveFlushEventListener; +import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.session.ReactiveSession; import org.hibernate.stat.spi.StatisticsImplementor; +import static java.lang.invoke.MethodHandles.lookup; +import static org.hibernate.reactive.logging.impl.LoggerFactory.make; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; /** @@ -24,6 +27,8 @@ public class DefaultReactiveFlushEventListener extends AbstractReactiveFlushingEventListener implements ReactiveFlushEventListener, FlushEventListener { + private static final Log LOG = make( Log.class, lookup() ); + @Override public CompletionStage reactiveOnFlush(FlushEvent event) throws HibernateException { final EventSource source = event.getSession(); @@ -59,6 +64,6 @@ else if ( ((ReactiveSession) source).getReactiveActionQueue().hasAnyQueuedAction @Override public void onFlush(FlushEvent event) throws HibernateException { - throw new UnsupportedOperationException(); + throw LOG.nonReactiveMethodCall( "reactiveOnFlush" ); } } diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/CustomOneToOneStoredProcedureSqlTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/CustomOneToOneStoredProcedureSqlTest.java new file mode 100644 index 000000000..ef542e8a3 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/CustomOneToOneStoredProcedureSqlTest.java @@ -0,0 +1,150 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.*; + +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLInsert; +import org.hibernate.reactive.testing.DBSelectionExtension; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + +import static java.util.concurrent.TimeUnit.*; +import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.*; +import static org.hibernate.reactive.testing.DBSelectionExtension.*; +import static org.junit.jupiter.api.Assertions.*; + +@Timeout(value = 10, timeUnit = MINUTES) + +public class CustomOneToOneStoredProcedureSqlTest extends BaseReactiveTest { + + @RegisterExtension + public DBSelectionExtension dbSelection = runOnlyFor( POSTGRESQL ); + private IndividualPerson individualPerson; + private DriverLicence driverLicence; + private static final String INITIAL_LICENCE_NO = "12545KLI12"; + private static final String INSERT_DRIVER_LICENCE_SQL = "CREATE OR REPLACE FUNCTION PROC_INSERT_INDIVIDUAL_PERSON_DRIVER_LICENCE995 ( " + + " ID_PARAM IN bigint, " + + " TEXT_PARAM IN varchar(255), " + + " ID_PERSON_PARAM IN bigint " + + " ) " + + " RETURNS void AS " + + "$BODY$ " + + " BEGIN " + + " insert into DRIVER_LICENCE (individual_person_Id, id, licenceNo, updated) values (ID_PERSON_PARAM, ID_PARAM, TEXT_PARAM, localtimestamp); " + + " END; " + + "$BODY$ " + + "LANGUAGE plpgsql;"; + + private static final String DELETE_DRIVER_LICENCE_SQL = "CREATE OR REPLACE FUNCTION PROC_DELETE_INDIVIDUAL_PERSON_DRIVER_LICENCE928 ( " + + " ID_PARAM IN bigint" + + " ) RETURNS void AS " + + "$BODY$ " + + " BEGIN " + + " update DRIVER_LICENCE set deleted=localtimestamp where id=ID_PARAM; " + + " END; " + + "$BODY$ " + + "LANGUAGE plpgsql;"; + + + @Override + protected Collection> annotatedEntities() { + return List.of( IndividualPerson.class, DriverLicence.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + individualPerson = new IndividualPerson(); + individualPerson.name = "Doruk"; + + driverLicence = new DriverLicence(); + driverLicence.licenceNo = INITIAL_LICENCE_NO; + driverLicence.individualPerson = individualPerson; + + test( context, openSession() + .thenCompose( s -> s + .createNativeQuery( INSERT_DRIVER_LICENCE_SQL ).executeUpdate() + .thenCompose( v -> s.createNativeQuery( DELETE_DRIVER_LICENCE_SQL ).executeUpdate() ) + .thenCompose( v -> s.persist( individualPerson, driverLicence ) ) + .thenCompose( v -> s.flush() ) + ) + ); + } + + @Test + public void testInsertStoredProcedureDriverLicence(VertxTestContext context) { + test( context, openSession().thenCompose( session -> session + .find( DriverLicence.class, driverLicence.id ) + .thenAccept( Assertions::assertNotNull ) ) + ); + } + + + @Test + public void testDeleteStoredProcedure(VertxTestContext context) { + test( context, openSession() + .thenCompose( session -> session + .find( DriverLicence.class, driverLicence.id ) + .thenCompose( session::remove ) + .thenCompose( v -> session.flush() ) ) + .thenCompose( v -> openSession() ) + .thenCompose( session -> session.find( DriverLicence.class, driverLicence.id ) ) + .thenAccept( foundRecord -> { + assertEquals( INITIAL_LICENCE_NO, foundRecord.licenceNo ); + assertNotNull( foundRecord.deleted ); + assertNotNull( foundRecord.updated ); + + } ) + ); + } + + @Entity + @Table(name = "DRIVER_LICENCE") + @SQLInsert(sql = "SELECT PROC_INSERT_INDIVIDUAL_PERSON_DRIVER_LICENCE995( $1, $2, $3 );", callable = true) + @SQLDelete(sql = "SELECT PROC_DELETE_INDIVIDUAL_PERSON_DRIVER_LICENCE928( $1 );", callable = true) + public static class DriverLicence { + @GeneratedValue + @Id + long id; + + @Basic(optional = false) + String licenceNo; + + @OneToOne + @JoinColumn(name = "individual_person_Id") + IndividualPerson individualPerson; + + @Column(insertable = false, updatable = false, nullable = false) + LocalDateTime updated; + + @Column(insertable = false, updatable = false) + LocalDateTime deleted; + + } + + @Entity(name = "INDIVIDUAL_PERSON") + @Table(name = "INDIVIDUAL_PERSON") + public static class IndividualPerson { + @GeneratedValue + @Id + long id; + + @Basic(optional = false) + String name; + + } + +} diff --git a/mytest.java b/mytest.java deleted file mode 100755 index 8274af30a..000000000 --- a/mytest.java +++ /dev/null @@ -1,210 +0,0 @@ -///usr/bin/env jbang "$0" "$@" ; exit $? -/* Hibernate, Relational Persistence for Idiomatic Java - * - * SPDX-License-Identifier: Apache-2.0 - * Copyright: Red Hat Inc. and Hibernate Authors - */ - -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.4.3} -//DEPS io.vertx:vertx-unit:${vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.0.0.Final} -//DEPS org.assertj:assertj-core:3.24.2 -//DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:mariadb:1.18.3 -//DEPS org.slf4j:slf4j-simple:2.0.7 - -//// Testcontainer needs the JDBC drivers to start the container -//// Hibernate Reactive doesn't need it -//DEPS org.mariadb.jdbc:mariadb-java-client:3.1.4 - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.Configuration; -import org.hibernate.reactive.mutiny.Mutiny; -import org.hibernate.reactive.provider.ReactiveServiceRegistryBuilder; -import org.hibernate.reactive.provider.Settings; - -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.JUnitCore; -import org.junit.runner.Result; -import org.junit.runner.RunWith; -import org.junit.runner.notification.Failure; - -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.testcontainers.containers.MariaDBContainer; -import org.testcontainers.utility.DockerImageName; - -import static org.assertj.core.api.Assertions.assertThat; - -//DESCRIPTION An example of a JUnit test class for Hibernate Reactive using -//DESCRIPTION [Vert.x Unit](https://vertx.io/docs/vertx-unit/java), -//DESCRIPTION [Testcontainers](https://www.testcontainers.org) -//DESCRIPTION and [MySQL](https://www.mysql.com/) -//DESCRIPTION that you can run using [JBang](JBang). -//DESCRIPTION -//DESCRIPTION Before running the tests, Testcontainers will start the selected -//DESCRIPTION Docker image with the required database created. -//DESCRIPTION -//DESCRIPTION Usage example: -//DESCRIPTION 1. Use as jbang template `jbang init -t mariadb-reproducer@hibernate/hibernate-reactive mytest.java` -//DESCRIPTION 2. Run the test with JBang: `jbang mytest.java` -//DESCRIPTION 3. (Optional) Edit the file (with IntelliJ IDEA for example): -//DESCRIPTION jbang edit --live --open=idea mytest.java -@RunWith(VertxUnitRunner.class) -public class mytest { - - public static DockerImageName imageName(String registry, String image, String version) { - return DockerImageName - .parse( registry + "/" + image + ":" + version ) - .asCompatibleSubstituteFor( image ); - } - - @ClassRule - public final static MariaDBContainer database = new MariaDBContainer<>( imageName( "docker.io", "mariadb", "10.11.3" ) ); - - private Mutiny.SessionFactory sessionFactory; - - @BeforeClass - public static void startContainer() { - database.start(); - } - - /** - * The {@link Configuration} for the {@link Mutiny.SessionFactory}. - */ - private Configuration createConfiguration() { - Configuration configuration = new Configuration(); - - // JDBC url - configuration.setProperty( Settings.URL, database.getJdbcUrl() ); - - // Credentials - configuration.setProperty( Settings.USER, database.getUsername() ); - configuration.setProperty( Settings.PASS, database.getPassword() ); - - // Schema generation. Supported values are create, drop, create-drop, drop-create, none - configuration.setProperty( Settings.HBM2DDL_AUTO, "create" ); - - // Register new entity classes here - configuration.addAnnotatedClass( MyEntity.class ); - - // (Optional) Log the SQL queries - configuration.setProperty( Settings.SHOW_SQL, "true" ); - configuration.setProperty( Settings.HIGHLIGHT_SQL, "true" ); - configuration.setProperty( Settings.FORMAT_SQL, "true" ); - return configuration; - } - - /* - * Create a new factory and a new schema before each test (see - * property `hibernate.hbm2ddl.auto`). - * This way each test will start with a clean database. - * - * The drawback is that, in a real case scenario with multiple tests, - * it can slow down the whole test suite considerably. If that happens, - * it's possible to make the session factory static and, if necessary, - * delete the content of the tables manually (without dropping them). - */ - @Before - public void createSessionFactory() { - Configuration configuration = createConfiguration(); - StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder() - .applySettings( configuration.getProperties() ); - StandardServiceRegistry registry = builder.build(); - - sessionFactory = configuration.buildSessionFactory( registry ) - .unwrap( Mutiny.SessionFactory.class ); - } - - @Test - public void testInsertAndSelect(TestContext context) { - // the test will wait until async.complete or context.fail are called - Async async = context.async(); - - MyEntity entity = new MyEntity( "first entity", 1 ); - sessionFactory - // insert the entity in the database - .withTransaction( (session, tx) -> session.persist( entity ) ) - .chain( () -> sessionFactory - .withSession( session -> session - // look for the entity by id - .find( MyEntity.class, entity.getId() ) - // assert that the returned entity is the right one - .invoke( foundEntity -> assertThat( foundEntity.getName() ).isEqualTo( entity.getName() ) ) ) ) - .subscribe() - .with( res -> async.complete(), context::fail ); - } - - @After - public void closeFactory() { - if ( sessionFactory != null ) { - sessionFactory.close(); - } - } - - /** - * Example of a class representing an entity. - *

- * If you create new entities, be sure to add them in . - * For example: - *

-	 * configuration.addAnnotatedClass( MyOtherEntity.class );
-	 * 
- */ - @Entity(name = "MyEntity") - public static class MyEntity { - @Id - public Integer id; - - public String name; - - public MyEntity() { - } - - public MyEntity(String name, Integer id) { - this.name = name; - this.id = id; - } - - public Integer getId() { - return id; - } - - public String getName() { - return name; - } - - @Override - public String toString() { - return "MyEntity" - + "\n\t id = " + id - + "\n\t name = " + name; - } - } - - // This main class is only for JBang so that it can run the tests with `jbang mytest.java` - public static void main(String[] args) { - System.out.println( "Starting the test suite with MariaDB"); - - Result result = JUnitCore.runClasses( mytest.class ); - - for ( Failure failure : result.getFailures() ) { - System.out.println(); - System.err.println( "Test " + failure.getTestHeader() + " FAILED!" ); - System.err.println( "\t" + failure.getTrace() ); - } - - System.out.println(); - System.out.print("Tests result summary: "); - System.out.println( result.wasSuccessful() ? "SUCCESS" : "FAILURE" ); - } -} diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index fe00a0690..ebc5e4554 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -7,7 +7,7 @@ //DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.4.3} //DEPS io.vertx:vertx-unit:$\{vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.0.Final} +//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.1.Final} //DEPS org.assertj:assertj-core:3.24.2 //DEPS junit:junit:4.13.2 //DEPS org.testcontainers:cockroachdb:1.18.3 diff --git a/tooling/jbang/Db2ReactiveTest.java.qute b/tooling/jbang/Db2ReactiveTest.java.qute index 9b0b80569..ab1166c4e 100755 --- a/tooling/jbang/Db2ReactiveTest.java.qute +++ b/tooling/jbang/Db2ReactiveTest.java.qute @@ -7,7 +7,7 @@ //DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.4.3} //DEPS io.vertx:vertx-unit:$\{vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.0.Final} +//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.1.Final} //DEPS org.assertj:assertj-core:3.24.2 //DEPS junit:junit:4.13.2 //DEPS org.testcontainers:db2:1.18.3 diff --git a/tooling/jbang/Example.java b/tooling/jbang/Example.java index 622014d51..cb6cb44ca 100644 --- a/tooling/jbang/Example.java +++ b/tooling/jbang/Example.java @@ -9,7 +9,7 @@ //DEPS io.vertx:vertx-pg-client:${vertx.version:4.4.3} //DEPS io.vertx:vertx-mysql-client:${vertx.version:4.4.3} //DEPS io.vertx:vertx-db2-client:${vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.0.0.Final} +//DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.0.1.Final} //DEPS org.slf4j:slf4j-simple:2.0.7 //DESCRIPTION Allow authentication to PostgreSQL using SCRAM: diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index 512a0db62..907ad59f7 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -7,7 +7,7 @@ //DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.4.3} //DEPS io.vertx:vertx-unit:$\{vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.0.Final} +//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.1.Final} //DEPS org.assertj:assertj-core:3.24.2 //DEPS junit:junit:4.13.2 //DEPS org.testcontainers:mariadb:1.18.3 diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index fb6ae10ab..d3eebca08 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -7,7 +7,7 @@ //DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.4.3} //DEPS io.vertx:vertx-unit:$\{vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.0.Final} +//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.1.Final} //DEPS org.assertj:assertj-core:3.24.2 //DEPS junit:junit:4.13.2 //DEPS org.testcontainers:mysql:1.18.3 diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index 44094300b..6f16cc004 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -7,7 +7,7 @@ //DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.4.3} //DEPS io.vertx:vertx-unit:$\{vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.0.Final} +//DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.0.1.Final} //DEPS org.assertj:assertj-core:3.24.2 //DEPS junit:junit:4.13.2 //DEPS org.testcontainers:postgresql:1.18.3 diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index bab4c377c..dbb32da76 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -10,7 +10,7 @@ //DEPS io.vertx:vertx-db2-client:${vertx.version:4.4.3} //DEPS io.vertx:vertx-mysql-client:${vertx.version:4.4.3} //DEPS io.vertx:vertx-unit:${vertx.version:4.4.3} -//DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.0.0.Final} +//DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.0.1.Final} //DEPS org.assertj:assertj-core:3.24.2 //DEPS junit:junit:4.13.2 //DEPS org.testcontainers:postgresql:1.18.3