diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java index e0a0eb4e4..c561a4124 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java @@ -26,6 +26,8 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.query.Order; import org.hibernate.query.Page; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.reactive.common.AffectedEntities; import org.hibernate.reactive.common.Identifier; import org.hibernate.reactive.common.ResultSetMapping; @@ -957,6 +959,39 @@ default Uni lock(Object entity, LockModeType lockModeType) { */ MutationQuery createMutationQuery(String queryString); + /** + * Create an instance of {@link MutationQuery} for the given update tree. + * + * @param updateQuery the update criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) + */ + MutationQuery createMutationQuery(CriteriaUpdate updateQuery); + + /** + * Create an instance of {@link MutationQuery} for the given delete tree. + * + * @param deleteQuery the delete criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) + */ + MutationQuery createMutationQuery(CriteriaDelete deleteQuery); + + /** + * Create a {@link MutationQuery} from the given insert select criteria tree + * + * @param insert the insert select criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) + */ + MutationQuery createMutationQuery(JpaCriteriaInsert insert); + /** * Create an instance of {@link Query} for the given HQL/JPQL query * string or HQL/JPQL update or delete statement. In the case of an @@ -2327,7 +2362,7 @@ default Uni withStatelessTransaction(Function> w * @return an instance of {@link CriteriaBuilder} for creating * criteria queries. */ - CriteriaBuilder getCriteriaBuilder(); + HibernateCriteriaBuilder getCriteriaBuilder(); /** * Obtain the JPA {@link Metamodel} for the persistence unit. diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java index aecc99e37..f21bed53b 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java @@ -15,6 +15,7 @@ import org.hibernate.Cache; import org.hibernate.internal.SessionCreationOptions; import org.hibernate.internal.SessionFactoryImpl; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.reactive.common.spi.Implementor; import org.hibernate.reactive.context.Context; import org.hibernate.reactive.context.impl.BaseKey; @@ -30,7 +31,6 @@ import org.hibernate.stat.Statistics; import io.smallrye.mutiny.Uni; -import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.metamodel.Metamodel; import static org.hibernate.reactive.common.InternalStateAssertions.assertUseOnEventLoop; @@ -245,7 +245,7 @@ public Uni withStatelessTransaction(String tenantId, BiFunction( delegate.createReactiveQuery( queryString ), factory ); } + @Override + public MutationQuery createMutationQuery(CriteriaUpdate updateQuery) { + return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( updateQuery ), factory ); + } + + @Override + public MutationQuery createMutationQuery(CriteriaDelete deleteQuery) { + return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( deleteQuery ), factory ); + } + + @Override + public MutationQuery createMutationQuery(JpaCriteriaInsert insert) { + return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( insert ), factory ); + } + @Override @Deprecated public Query createQuery(String queryString) { return new MutinyQueryImpl<>( delegate.createReactiveQuery( queryString ), factory ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java index e67605c81..9b720b5a8 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java @@ -11,7 +11,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.query.criteria.JpaCriteriaInsertSelect; +import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.reactive.common.AffectedEntities; import org.hibernate.reactive.common.ResultSetMapping; import org.hibernate.reactive.query.ReactiveMutationQuery; @@ -79,7 +79,7 @@ public interface ReactiveQueryProducer extends ReactiveConnectionSupplier { ReactiveMutationQuery createReactiveMutationQuery(CriteriaDelete deleteQuery); - ReactiveMutationQuery createReactiveMutationQuery(JpaCriteriaInsertSelect insertSelect); + ReactiveMutationQuery createReactiveMutationQuery(JpaCriteriaInsert insert); ReactiveMutationQuery createNativeReactiveMutationQuery(String sqlString); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java index c746c9547..f81eab1f9 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java @@ -69,7 +69,7 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.query.IllegalMutationQueryException; -import org.hibernate.query.criteria.JpaCriteriaInsertSelect; +import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.hql.spi.SqmQueryImplementor; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.spi.HqlInterpretation; @@ -78,7 +78,7 @@ import org.hibernate.query.sqm.internal.SqmUtil; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; -import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.query.sqm.tree.select.SqmQueryGroup; import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; @@ -543,10 +543,10 @@ public ReactiveMutationQuery createReactiveMutationQuery(CriteriaDelete ReactiveMutationQuery createReactiveMutationQuery(JpaCriteriaInsertSelect insertSelect) { + public ReactiveMutationQuery createReactiveMutationQuery(JpaCriteriaInsert insert) { checkOpen(); try { - return createReactiveCriteriaQuery( (SqmInsertSelectStatement) insertSelect, null ); + return createReactiveCriteriaQuery( (SqmInsertStatement) insert, null ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java index 5e02b9389..2e9dd3df1 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java @@ -45,7 +45,7 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.query.IllegalMutationQueryException; -import org.hibernate.query.criteria.JpaCriteriaInsertSelect; +import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.hql.spi.SqmQueryImplementor; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.spi.HqlInterpretation; @@ -55,7 +55,7 @@ import org.hibernate.query.sqm.internal.SqmUtil; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; -import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.query.sqm.tree.select.SqmQueryGroup; import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; @@ -998,10 +998,10 @@ public ReactiveMutationQuery createReactiveMutationQuery(CriteriaDelete ReactiveMutationQuery createReactiveMutationQuery(JpaCriteriaInsertSelect insertSelect) { + public ReactiveMutationQuery createReactiveMutationQuery(JpaCriteriaInsert insert) { checkOpen(); try { - return createReactiveCriteriaQuery( (SqmInsertSelectStatement) insertSelect, null ); + return createReactiveCriteriaQuery( (SqmInsertStatement) insert, null ); } catch ( RuntimeException e ) { throw getExceptionConverter().convert( e ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java index f009b8dca..7741201a0 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java @@ -27,6 +27,8 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.query.Order; import org.hibernate.query.Page; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.reactive.common.AffectedEntities; import org.hibernate.reactive.common.Identifier; import org.hibernate.reactive.common.ResultSetMapping; @@ -994,6 +996,39 @@ default CompletionStage lock(Object entity, LockModeType lockModeType) { */ MutationQuery createMutationQuery(String queryString); + /** + * Create an instance of {@link MutationQuery} for the given update tree. + * + * @param updateQuery the update criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) + */ + MutationQuery createMutationQuery(CriteriaUpdate updateQuery); + + /** + * Create an instance of {@link MutationQuery} for the given delete tree. + * + * @param deleteQuery the delete criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) + */ + MutationQuery createMutationQuery(CriteriaDelete deleteQuery); + + /** + * Create a {@link MutationQuery} from the given insert select criteria tree + * + * @param insert the insert select criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) + */ + MutationQuery createMutationQuery(JpaCriteriaInsert insert); + /** * Create an instance of {@link Query} for the given HQL/JPQL query * string or HQL/JPQL update or delete statement. In the case of an @@ -1663,6 +1698,39 @@ default CompletionStage get(Class entityClass, Object id, LockModeType */ MutationQuery createMutationQuery(String queryString); + /** + * Create an instance of {@link MutationQuery} for the given update tree. + * + * @param updateQuery the update criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) + */ + MutationQuery createMutationQuery(CriteriaUpdate updateQuery); + + /** + * Create an instance of {@link MutationQuery} for the given delete tree. + * + * @param deleteQuery the delete criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) + */ + MutationQuery createMutationQuery(CriteriaDelete deleteQuery); + + /** + * Create a {@link MutationQuery} from the given insert select criteria tree + * + * @param insert the insert select criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) + */ + MutationQuery createMutationQuery(JpaCriteriaInsert insert); + /** * Create an instance of {@link Query} for the given SQL query string, * or SQL update, insert, or delete statement. In the case of an update, @@ -2362,7 +2430,7 @@ default CompletionStage withStatelessTransaction(Function( delegate.createReactiveMutationQuery( queryString ) ); } + @Override + public MutationQuery createMutationQuery(CriteriaUpdate updateQuery) { + return new StageMutationQueryImpl<>( delegate.createReactiveMutationQuery( updateQuery ) ); + } + + @Override + public MutationQuery createMutationQuery(CriteriaDelete deleteQuery) { + return new StageMutationQueryImpl<>( delegate.createReactiveMutationQuery( deleteQuery ) ); + } + + @Override + public MutationQuery createMutationQuery(JpaCriteriaInsert insert) { + return new StageMutationQueryImpl<>( delegate.createReactiveMutationQuery( insert ) ); + } + @Override public CompletionStage find(Class entityClass, Object primaryKey) { return delegate.reactiveFind( entityClass, primaryKey, null, null ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java index 6e05c747c..0d7c5d834 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java @@ -11,6 +11,7 @@ import jakarta.persistence.criteria.CriteriaUpdate; import org.hibernate.LockMode; import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.reactive.common.ResultSetMapping; import org.hibernate.reactive.pool.ReactiveConnection; import org.hibernate.reactive.session.ReactiveStatelessSession; @@ -276,6 +277,21 @@ public MutationQuery createMutationQuery(String queryString) { return new StageMutationQueryImpl<>( delegate.createReactiveMutationQuery( queryString ) ); } + @Override + public MutationQuery createMutationQuery(CriteriaUpdate updateQuery) { + return new StageMutationQueryImpl<>( delegate.createReactiveMutationQuery( updateQuery ) ); + } + + @Override + public MutationQuery createMutationQuery(CriteriaDelete deleteQuery) { + return new StageMutationQueryImpl<>( delegate.createReactiveMutationQuery( deleteQuery ) ); + } + + @Override + public MutationQuery createMutationQuery(JpaCriteriaInsert insert) { + return new StageMutationQueryImpl<>( delegate.createReactiveMutationQuery( insert ) ); + } + @Override public SelectionQuery createQuery(String queryString, Class resultType) { return new StageSelectionQueryImpl<>( delegate.createReactiveQuery( queryString, resultType ) ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/CriteriaMutationQueryTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/CriteriaMutationQueryTest.java new file mode 100644 index 000000000..356a93bd3 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/CriteriaMutationQueryTest.java @@ -0,0 +1,326 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaInsertSelect; +import org.hibernate.query.criteria.JpaCriteriaInsertValues; +import org.hibernate.query.criteria.JpaCriteriaQuery; +import org.hibernate.query.criteria.JpaRoot; +import org.hibernate.reactive.mutiny.Mutiny; +import org.hibernate.reactive.stage.Stage; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Tuple; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.criteria.Root; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 10, timeUnit = MINUTES) +public class CriteriaMutationQueryTest extends BaseReactiveTest { + private static final Integer SPELT_ID = 1; + private static final String SPELT_NAME = "Spelt"; + private static final String SPELT_TYPE = "Wheat flour"; + Flour spelt = new Flour( SPELT_ID, SPELT_NAME, "An ancient grain, is a hexaploid species of wheat.", SPELT_TYPE ); + Flour rye = new Flour( 2, "Rye", "Used to bake the traditional sourdough breads of Germany.", "Wheat flour" ); + Flour almond = new Flour( 3, "Almond", "made from ground almonds.", "Gluten free" ); + + @Override + protected Collection> annotatedEntities() { + return List.of( Flour.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + test( context, getSessionFactory().withTransaction( s -> s.persist( spelt, rye, almond ) ) ); + } + + @Test + public void testStageUpdateCriteriaQuery(VertxTestContext context) { + String updatedDescription = "Most rye breads use a mix of rye and wheat flours"; + test( context, getSessionFactory() + .withTransaction( s -> s + .createMutationQuery( criteriaUpdate( getCriteriaBuilder( s ), updatedDescription, rye ) ) + .executeUpdate() + ) + .thenAccept( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .thenCompose( v -> getSessionFactory() + .withTransaction( s -> s.find( Flour.class, rye.getId() ) ) ) + .thenAccept( result -> assertThat( result.getDescription() ).isEqualTo( updatedDescription ) ) + ); + } + + @Test + public void testMutinyUpdateCriteriaQuery(VertxTestContext context) { + String updatedDescription = "made from ground almonds."; + test( context, getMutinySessionFactory() + .withTransaction( s -> s + .createMutationQuery( criteriaUpdate( getCriteriaBuilder( s ), updatedDescription, almond ) ) + .executeUpdate() + ) + .invoke( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( Flour.class, almond.getId() ) ) ) + .invoke( result -> assertThat( result.getDescription() ).isEqualTo( updatedDescription ) ) + ); + } + + @Test + public void testStageDeleteCriteriaQuery(VertxTestContext context) { + test( context, getSessionFactory() + .withTransaction( s -> s + .createMutationQuery( criteriaUpdate( getCriteriaBuilder( s ) ) ) + .executeUpdate() + ) + .thenAccept( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .thenCompose( v -> getSessionFactory() + .withTransaction( s -> s.find( Flour.class, spelt.getId() ) ) ) + .thenAccept( result -> assertThat( result ).isNull() ) + ); + } + + @Test + public void testMutinyDeleteCriteriaQuery(VertxTestContext context) { + test( context, getMutinySessionFactory() + .withTransaction( s -> { + return s.createMutationQuery( criteriaUpdate( getCriteriaBuilder( s ) ) ).executeUpdate(); + } ) + .invoke( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( Flour.class, spelt.getId() ) ) ) + .invoke( result -> assertThat( result ).isNull() ) + ); + } + + @Test + public void testStageInsertCriteriaQuery(VertxTestContext context) { + final int id = 4; + final String flourName = "Rye"; + final String flourDescription = "Used to bake the traditional sourdough breads of Germany."; + final String flourType = "Wheat flour"; + test( context, getSessionFactory() + .withTransaction( s -> s + .createMutationQuery( insertCriteria( getCriteriaBuilder( s ), id, flourName, flourDescription, flourType ) ) + .executeUpdate() + ) + .thenAccept( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .thenCompose( v -> getSessionFactory() + .withTransaction( s -> s.find( Flour.class, id ) ) ) + .thenAccept( result -> { + assertThat( result ).isNotNull(); + assertThat( result.name ).isEqualTo( flourName ); + assertThat( result.description ).isEqualTo( flourDescription ); + assertThat( result.type ).isEqualTo( flourType ); + } ) + ); + } + + @Test + public void testMutinyInsertCriteriaQuery(VertxTestContext context) { + final int id = 4; + final String flourName = "Almond"; + final String flourDescription = "made from ground almonds."; + final String flourType = "Gluten free"; + test( context, getMutinySessionFactory() + .withTransaction( s -> s + .createMutationQuery( insertCriteria( getCriteriaBuilder( s ), id, flourName, flourDescription, flourType ) ) + .executeUpdate() + ) + .invoke( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( Flour.class, id ) ) ) + .invoke( result -> { + assertThat( result ).isNotNull(); + assertThat( result.name ).isEqualTo( flourName ); + assertThat( result.description ).isEqualTo( flourDescription ); + assertThat( result.type ).isEqualTo( flourType ); + } ) + ); + } + + @Test + public void testStageInsertSelectCriteriaQuery(VertxTestContext context) { + final int idOfTheNewFlour = 4; + test( context, getSessionFactory() + .withTransaction( s -> s + .createMutationQuery( insertSelectCriteria( getCriteriaBuilder( s ), idOfTheNewFlour ) ) + .executeUpdate() + ) + .thenAccept( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .thenCompose( v -> getSessionFactory() + .withTransaction( s -> s.find( Flour.class, idOfTheNewFlour ) ) ) + .thenAccept( result -> { + assertThat( result ).isNotNull(); + assertThat( result.name ).isEqualTo( SPELT_NAME ); + assertThat( result.description ).isNull(); + assertThat( result.type ).isEqualTo( SPELT_TYPE ); + } ) + ); + } + + @Test + public void testMutinyInsertSelectCriteriaQuery(VertxTestContext context) { + final int idOfTheNewFlour = 4; + test( context, getMutinySessionFactory() + .withTransaction( s -> s + .createMutationQuery( insertSelectCriteria( getCriteriaBuilder( s ), idOfTheNewFlour ) ) + .executeUpdate() + ) + .invoke( resultCount -> assertThat( resultCount ).isEqualTo( 1 ) ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( Flour.class, idOfTheNewFlour ) ) ) + .invoke( result -> { + assertThat( result ).isNotNull(); + assertThat( result.name ).isEqualTo( SPELT_NAME ); + assertThat( result.description ).isNull(); + assertThat( result.type ).isEqualTo( SPELT_TYPE ); + } ) + ); + } + + private CriteriaUpdate criteriaUpdate(CriteriaBuilder cb, String updatedDescription, Flour rye) { + CriteriaUpdate criteriaUpdate = cb.createCriteriaUpdate( Flour.class ); + Root from = criteriaUpdate.from( Flour.class ); + criteriaUpdate.set( from.get( "description" ), updatedDescription ); + criteriaUpdate.where( cb.equal( from.get( "id" ), rye.getId() ) ); + return criteriaUpdate; + } + + private CriteriaDelete criteriaUpdate(CriteriaBuilder criteriaBuilder) { + CriteriaDelete criteriaDelete = criteriaBuilder.createCriteriaDelete( Flour.class ); + Root from = criteriaDelete.from( Flour.class ); + criteriaDelete.where( criteriaBuilder.equal( from.get( "id" ), spelt.getId() ) ); + return criteriaDelete; + } + + private static JpaCriteriaInsertValues insertCriteria(HibernateCriteriaBuilder cb, int id, String name, String description, String type) { + JpaCriteriaInsertValues insert = cb.createCriteriaInsertValues( Flour.class ); + JpaRoot flour = insert.getTarget(); + insert.setInsertionTargetPaths( flour.get( "id" ), flour.get( "name" ), flour.get( "description" ), flour.get( "type" ) ); + insert.values( cb.values( cb.value( id ), cb.value( name ), cb.value( description ), cb.value( type ) ) ); + return insert; + } + + private static JpaCriteriaInsertSelect insertSelectCriteria( + HibernateCriteriaBuilder cb, + int idOfTheNewFlour) { + /* + The query executes and insert of Flour with id equals to 2 a name and type + selected from the existing spelt flour saved in the db + */ + JpaCriteriaInsertSelect insertSelect = cb.createCriteriaInsertSelect( Flour.class ); + // columns to insert + JpaRoot flour = insertSelect.getTarget(); + insertSelect.setInsertionTargetPaths( flour.get( "id" ), flour.get( "name" ), flour.get( "type" ) ); + // select query + JpaCriteriaQuery select = cb.createQuery( Tuple.class ); + JpaRoot root = select.from( Flour.class ); + select.multiselect( cb.literal( idOfTheNewFlour ), root.get( "name" ), root.get( "type" ) ); + select.where( cb.equal( root.get( "id" ), SPELT_ID ) ); + + insertSelect.select( select ); + return insertSelect; + } + + private static HibernateCriteriaBuilder getCriteriaBuilder(Stage.Session session) { + return session.getFactory().getCriteriaBuilder(); + } + + private static HibernateCriteriaBuilder getCriteriaBuilder(Mutiny.Session session) { + return session.getFactory().getCriteriaBuilder(); + } + + @Entity(name = "Flour") + @Table(name = "Flour") + public static class Flour { + @Id + private Integer id; + private String name; + private String description; + private String type; + + public Flour() { + } + + public Flour(Integer id, String name, String description, String type) { + this.id = id; + this.name = name; + this.description = description; + this.type = type; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Flour flour = (Flour) o; + return Objects.equals( name, flour.name ) && + Objects.equals( description, flour.description ) && + Objects.equals( type, flour.type ); + } + + @Override + public int hashCode() { + return Objects.hash( name, description, type ); + } + } +}