diff --git a/README.md b/README.md index c01979d65..509706206 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 7.0.0.Beta4 +- [Hibernate ORM][] 7.0.0.CR1 - [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.14 - [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.14 - [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.14 diff --git a/gradle.properties b/gradle.properties index 3576439d6..c402bb33b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 7.0.0.Beta5 +hibernateOrmVersion = 7.0.0.CR1 # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from # a remote repository -#hibernateOrmGradlePluginVersion = 7.0.0.Beta4 +#hibernateOrmGradlePluginVersion = 7.0.0.CR1 # If set to true, skip Hibernate ORM version parsing (default is true, if set to null) # this is required when using intervals or weird versions or the build will fail diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java index 70495ccea..e842adf11 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java @@ -5,13 +5,6 @@ */ package org.hibernate.reactive.generator.values.internal; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletionStage; - import org.hibernate.HibernateException; import org.hibernate.Internal; import org.hibernate.dialect.Dialect; @@ -48,8 +41,15 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.type.descriptor.WrapperOptions; -import static org.hibernate.generator.internal.NaturalIdHelper.getNaturalIdPropertyNames; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletionStage; + import static org.hibernate.generator.values.internal.GeneratedValuesHelper.noCustomSql; +import static org.hibernate.internal.NaturalIdHelper.getNaturalIdPropertyNames; import static org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.UniqueSemantic.NONE; /** diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java index 527d59326..71ae6e7e7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java @@ -10,7 +10,7 @@ import java.util.concurrent.CompletionStage; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.event.spi.EventSource; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; @@ -50,7 +50,7 @@ public EntityMappingType getLoadable() { } @Override - public final CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions loadOptions, EventSource session) { + public final CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions loadOptions, SharedSessionContractImplementor session) { Objects.requireNonNull( ids ); return loadOptions.isOrderReturnEnabled() @@ -58,8 +58,8 @@ public final CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptio : performUnorderedMultiLoad( ids, loadOptions, session ); } - protected abstract CompletionStage> performOrderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, EventSource session); + protected abstract CompletionStage> performOrderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, SharedSessionContractImplementor session); - protected abstract CompletionStage> performUnorderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, EventSource session); + protected abstract CompletionStage> performUnorderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, SharedSessionContractImplementor session); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java index 8239a6e15..612e5ad16 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java @@ -18,8 +18,8 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SubselectFetch; -import org.hibernate.event.spi.EventSource; import org.hibernate.loader.ast.internal.LoaderSelectBuilder; import org.hibernate.loader.ast.internal.MultiIdEntityLoaderArrayParam; import org.hibernate.loader.ast.internal.MultiKeyLoadLogging; @@ -82,7 +82,7 @@ public BasicEntityIdentifierMapping getIdentifierMapping() { protected CompletionStage> performOrderedMultiLoad( K[] ids, MultiIdLoadOptions loadOptions, - EventSource session) { + SharedSessionContractImplementor session) { if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef( "ReactiveMultiIdEntityLoaderArrayParam#performOrderedMultiLoad - %s", @@ -227,7 +227,7 @@ protected CompletionStage> performOrderedMultiLoad( protected CompletionStage> performUnorderedMultiLoad( K[] ids, MultiIdLoadOptions loadOptions, - EventSource session) { + SharedSessionContractImplementor session) { if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef( "ReactiveMultiIdEntityLoaderArrayParam#performUnorderedMultiLoad - %s", @@ -305,7 +305,7 @@ protected final K[] processResolvableEntities( MultiIdEntityLoaderArrayParam.ResolutionConsumer resolutionConsumer, MultiIdLoadOptions loadOptions, LockOptions lockOptions, - EventSource session) { + SharedSessionContractImplementor session) { if ( !loadOptions.isSessionCheckingEnabled() && !loadOptions.isSecondLevelCacheCheckingEnabled() ) { // we'll load all of them from the database diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java index 92f4e996a..743078403 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java @@ -24,7 +24,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SubselectFetch; -import org.hibernate.event.spi.EventSource; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.loader.ast.internal.LoaderSelectBuilder; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; @@ -75,7 +74,7 @@ public ReactiveMultiIdEntityLoaderStandard( protected CompletionStage> performOrderedMultiLoad( Object[] ids, MultiIdLoadOptions loadOptions, - EventSource session) { + SharedSessionContractImplementor session) { if ( LOG.isTraceEnabled() ) { LOG.tracef( "#performOrderedMultiLoad(`%s`, ..)", getEntityDescriptor().getEntityName() ); } @@ -289,7 +288,7 @@ private static List singletonList(Object loaded) { protected CompletionStage> performUnorderedMultiLoad( Object[] ids, MultiIdLoadOptions loadOptions, - EventSource session) { + SharedSessionContractImplementor session) { assert !loadOptions.isOrderReturnEnabled(); assert ids != null; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java index 684894cf2..c23a00983 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java @@ -55,8 +55,7 @@ public CompletionStage load( SharedSessionContractImplementor session) { final ReactiveSingleIdLoadPlan loadPlan = (ReactiveSingleIdLoadPlan) resolveLoadPlan( lockOptions, - session.getLoadQueryInfluencers(), - session.getFactory() + session.getLoadQueryInfluencers() ); return loadPlan.load( key, readOnly, true, session ); } @@ -68,7 +67,7 @@ public CompletionStage load( LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { - final ReactiveSingleIdLoadPlan loadPlan = (ReactiveSingleIdLoadPlan) resolveLoadPlan( lockOptions, session.getLoadQueryInfluencers(), session.getFactory() ); + final ReactiveSingleIdLoadPlan loadPlan = (ReactiveSingleIdLoadPlan) resolveLoadPlan( lockOptions, session.getLoadQueryInfluencers() ); return loadPlan.load( key, entityInstance, readOnly, false, session ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java index 47050b139..e0236e361 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.concurrent.CompletionStage; -import org.hibernate.event.spi.EventSource; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.loader.ast.spi.MultiIdEntityLoader; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.reactive.logging.impl.Log; @@ -22,9 +22,9 @@ public interface ReactiveMultiIdEntityLoader extends MultiIdEntityLoader { @Override - default List load(K[] ids, MultiIdLoadOptions options, EventSource session) { + default List load(K[] ids, MultiIdLoadOptions options, SharedSessionContractImplementor session) { throw make( Log.class, lookup() ).nonReactiveMethodCall( "reactiveLoad" ); } - CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions options, EventSource session); + CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions options, SharedSessionContractImplementor session); } 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 0f231ff63..c73c6b416 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 @@ -5,11 +5,6 @@ */ package org.hibernate.reactive.mutiny; -import java.lang.invoke.MethodHandles; -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.Function; - import org.hibernate.Cache; import org.hibernate.CacheMode; import org.hibernate.Filter; @@ -23,7 +18,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.jpa.internal.util.FlushModeTypeHelper; 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; @@ -43,12 +37,17 @@ import jakarta.persistence.FlushModeType; import jakarta.persistence.LockModeType; import jakarta.persistence.Parameter; +import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.metamodel.Attribute; import jakarta.persistence.metamodel.Metamodel; +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; @@ -360,37 +359,6 @@ default SelectionQuery setLockMode(String alias, LockModeType lockModeType) { return setLockMode( alias, convertToLockMode(lockModeType) ); } -// /** -// * Set the {@link LockOptions} to use for the whole query. -// * -// * @see org.hibernate.query.Query#setLockOptions(LockOptions) -// */ -// Query setLockOptions(LockOptions lockOptions); - - /** - * If the result type of this query is an entity class, add one or more - * {@linkplain Order rules} for ordering the query results. - * - * @param orderList one or more instances of {@link Order} - * - * @see Order - * - * @see org.hibernate.query.Query#setOrder(List) - */ - SelectionQuery setOrder(List> orderList); - - /** - * If the result type of this query is an entity class, add a - * {@linkplain Order rule} for ordering the query results. - * - * @param order an instance of {@link Order} - * - * @see Order - * - * @see org.hibernate.query.Query#setOrder(Order) - */ - SelectionQuery setOrder(Order order); - /** * Set the {@link EntityGraph} that will be used as a fetch plan for * the root entity returned by this query. @@ -994,6 +962,22 @@ default Uni lock(Object entity, LockModeType lockModeType) { */ MutationQuery createMutationQuery(JpaCriteriaInsert insert); + /** + * Create a typed {@link org.hibernate.query.Query} instance for the given typed query reference. + * + * @param typedQueryReference the type query reference + * + * @return The {@link org.hibernate.query.Query} instance for execution + * + * @throws IllegalArgumentException if a query has not been + * defined with the name of the typed query reference or if + * the query result is found to not be assignable to + * result class of the typed query reference + * + * @see org.hibernate.query.QueryProducer#createQuery(TypedQueryReference) + */ + Query createQuery(TypedQueryReference typedQueryReference); + /** * 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 @@ -1649,6 +1633,22 @@ default Uni get(Class entityClass, Object id, LockModeType lockModeTyp @Deprecated Query createQuery(String queryString); + /** + * Create a typed {@link Query} instance for the given typed query reference. + * + * @param typedQueryReference the type query reference + * + * @return The {@link Query} instance for execution + * + * @throws IllegalArgumentException if a query has not been + * defined with the name of the typed query reference or if + * the query result is found to not be assignable to + * result class of the typed query reference + * + * @see org.hibernate.query.QueryProducer#createQuery(TypedQueryReference) + */ + Query createQuery(TypedQueryReference typedQueryReference); + /** * Create an instance of {@link SelectionQuery} for the given HQL/JPQL * query string and query result type. diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyQueryImpl.java index d0608ba5f..88243f77d 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyQueryImpl.java @@ -5,16 +5,11 @@ */ package org.hibernate.reactive.mutiny.impl; -import java.util.List; -import java.util.concurrent.CompletionStage; -import java.util.function.Supplier; - import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockMode; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.query.Order; import org.hibernate.query.Page; import org.hibernate.reactive.mutiny.Mutiny; import org.hibernate.reactive.mutiny.Mutiny.Query; @@ -27,6 +22,9 @@ import jakarta.persistence.FlushModeType; import jakarta.persistence.LockModeType; import jakarta.persistence.Parameter; +import java.util.List; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; public class MutinyQueryImpl implements Query { @@ -74,18 +72,6 @@ public Query setLockMode(LockMode lockMode) { return this; } - @Override - public Mutiny.SelectionQuery setOrder(List> orders) { - delegate.setOrder( orders ); - return this; - } - - @Override - public Mutiny.SelectionQuery setOrder(Order order) { - delegate.setOrder( (List>) order ); - return this; - } - @Override public Query setPlan(EntityGraph entityGraph) { delegate.applyGraph( (RootGraphImplementor) entityGraph, GraphSemantic.FETCH ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySelectionQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySelectionQueryImpl.java index b001e618a..fb4fe2ad2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySelectionQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySelectionQueryImpl.java @@ -5,16 +5,11 @@ */ package org.hibernate.reactive.mutiny.impl; -import java.util.List; -import java.util.concurrent.CompletionStage; -import java.util.function.Supplier; - import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockMode; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.query.Order; import org.hibernate.query.Page; import org.hibernate.reactive.mutiny.Mutiny.SelectionQuery; import org.hibernate.reactive.query.ReactiveSelectionQuery; @@ -26,6 +21,9 @@ import jakarta.persistence.FlushModeType; import jakarta.persistence.LockModeType; import jakarta.persistence.Parameter; +import java.util.List; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; public class MutinySelectionQueryImpl implements SelectionQuery { private final MutinySessionFactoryImpl factory; @@ -196,19 +194,6 @@ public SelectionQuery setLockMode(String alias, LockMode lockMode) { return this; } - @Override - public SelectionQuery setOrder(List> orders) { - delegate.setOrder( orders ); - return this; - } - - @Override - public SelectionQuery setOrder(Order order) { - delegate.setOrder( order ); - return this; - } - - @Override public SelectionQuery setParameter(String name, Object value) { delegate.setParameter( name, value ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java index 87cf50bb0..ab57ee718 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java @@ -12,6 +12,7 @@ import jakarta.persistence.FlushModeType; import jakarta.persistence.LockModeType; import jakarta.persistence.PersistenceException; +import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; @@ -34,6 +35,7 @@ import org.hibernate.reactive.mutiny.Mutiny.Query; import org.hibernate.reactive.mutiny.Mutiny.SelectionQuery; import org.hibernate.reactive.pool.ReactiveConnection; +import org.hibernate.reactive.query.ReactiveQuery; import org.hibernate.reactive.session.ReactiveConnectionSupplier; import org.hibernate.reactive.session.ReactiveQueryProducer; import org.hibernate.reactive.session.ReactiveSession; @@ -140,6 +142,12 @@ public MutationQuery createMutationQuery(JpaCriteriaInsert insert) { return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( insert ), factory ); } + @Override + public Query createQuery(TypedQueryReference typedQueryReference) { + ReactiveQuery reactiveQuery = delegate.createReactiveQuery( typedQueryReference ); + return new MutinyQueryImpl<>( reactiveQuery, 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/mutiny/impl/MutinyStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java index 5605a7911..cb7db4a8e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java @@ -7,6 +7,7 @@ import io.smallrye.mutiny.Uni; import jakarta.persistence.EntityGraph; +import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; @@ -17,6 +18,7 @@ import org.hibernate.reactive.mutiny.Mutiny.Query; import org.hibernate.reactive.mutiny.Mutiny.SelectionQuery; import org.hibernate.reactive.pool.ReactiveConnection; +import org.hibernate.reactive.query.ReactiveQuery; import org.hibernate.reactive.session.ReactiveStatelessSession; import java.util.List; @@ -71,6 +73,12 @@ public Uni get(EntityGraph entityGraph, Object id) { return uni( () -> delegate.reactiveGet( entityClass, id, null, entityGraph ) ); } + @Override + public Query createQuery(TypedQueryReference typedQueryReference) { + ReactiveQuery reactiveQuery = delegate.createReactiveQuery( typedQueryReference ); + return new MutinyQueryImpl<>( reactiveQuery, factory ); + } + @Override public Query createQuery(String queryString) { return new MutinyQueryImpl<>( delegate.createReactiveQuery( queryString ), factory ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractPersisterDelegate.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractPersisterDelegate.java index 9a31d2bc8..c5d068db7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractPersisterDelegate.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractPersisterDelegate.java @@ -20,11 +20,11 @@ import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.spi.EventSource; import org.hibernate.generator.Generator; import org.hibernate.generator.values.GeneratedValues; import org.hibernate.id.IdentityGenerator; import org.hibernate.loader.ast.spi.BatchLoaderFactory; +import org.hibernate.loader.ast.spi.EntityBatchLoader; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; @@ -81,11 +81,11 @@ public class ReactiveAbstractPersisterDelegate { private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() ); - private final Supplier> singleIdEntityLoaderSupplier; - private final Supplier> multiIdEntityLoaderSupplier; + private final Supplier> singleIdEntityLoaderSupplier; + private final Supplier> multiIdEntityLoaderSupplier; - private ReactiveSingleIdEntityLoader singleIdEntityLoader; - private ReactiveMultiIdEntityLoader multiIdEntityLoader; + private ReactiveSingleIdEntityLoader singleIdEntityLoader; + private ReactiveMultiIdEntityLoader multiIdEntityLoader; private final EntityPersister entityDescriptor; @@ -101,12 +101,12 @@ public ReactiveAbstractPersisterDelegate( entityDescriptor = entityPersister; } - public ReactiveSingleIdEntityLoader buildSingleIdEntityLoader() { + public ReactiveSingleIdEntityLoader buildSingleIdEntityLoader() { singleIdEntityLoader = singleIdEntityLoaderSupplier.get(); return singleIdEntityLoader; } - public ReactiveMultiIdEntityLoader buildMultiIdEntityLoader() { + public ReactiveMultiIdEntityLoader buildMultiIdEntityLoader() { multiIdEntityLoader = multiIdEntityLoaderSupplier.get(); return multiIdEntityLoader; } @@ -126,7 +126,7 @@ public DomainResult createDomainResult( /** * @see org.hibernate.persister.entity.AbstractEntityPersister#multiLoad(Object[], EventSource, MultiIdLoadOptions)` */ - public CompletionStage> multiLoad(K[] ids, EventSource session, MultiIdLoadOptions loadOptions) { + public CompletionStage> multiLoad(K[] ids, SharedSessionContractImplementor session, MultiIdLoadOptions loadOptions) { return multiIdEntityLoader.reactiveLoad( ids, loadOptions, session ); } @@ -135,12 +135,12 @@ private static ReactiveMultiIdEntityLoader buildMultiIdEntityLoader( PersistentClass persistentClass, SessionFactoryImplementor factory) { return entityDescriptor.getIdentifierType() instanceof BasicType - && supportsSqlArrayType( factory.getJdbcServices().getDialect() ) + && supportsSqlArrayType( factory.getJdbcServices().getDialect() ) ? new ReactiveMultiIdEntityLoaderArrayParam<>( entityDescriptor, factory ) : new ReactiveMultiIdEntityLoaderStandard<>( entityDescriptor, persistentClass, factory ); } - private static ReactiveSingleIdEntityLoader buildSingleIdEntityLoader( + private static ReactiveSingleIdEntityLoader buildSingleIdEntityLoader( EntityPersister entityDescriptor, PersistentClass bootDescriptor, RuntimeModelCreationContext creationContext, @@ -148,32 +148,45 @@ private static ReactiveSingleIdEntityLoader buildSingleIdEntityLoader( String entityName) { if ( bootDescriptor.getLoaderName() != null ) { // We must resolve the named query on-demand through the boot model because it isn't initialized yet - final NamedQueryMemento namedQueryMemento = factory.getQueryEngine().getNamedObjectRepository() - .resolve( factory, creationContext.getBootModel(), bootDescriptor.getLoaderName() ); - if ( namedQueryMemento == null ) { - throw new IllegalArgumentException( "Could not resolve named load-query [" + entityName + "] : " + bootDescriptor.getLoaderName() ); - } + final NamedQueryMemento namedQueryMemento = + getNamedQueryMemento( bootDescriptor, creationContext, factory, entityName ); return new ReactiveSingleIdEntityLoaderProvidedQueryImpl<>( entityDescriptor, namedQueryMemento ); } - - LoadQueryInfluencers loadQueryInfluencers = new LoadQueryInfluencers( factory ); - if ( loadQueryInfluencers.effectivelyBatchLoadable( entityDescriptor ) ) { - final int batchSize = loadQueryInfluencers.effectiveBatchSize( entityDescriptor ); - if ( batchSize > 1 ) { + else { + final LoadQueryInfluencers loadQueryInfluencers = new LoadQueryInfluencers( factory ); + if ( loadQueryInfluencers.effectivelyBatchLoadable( entityDescriptor ) ) { + final int batchSize = loadQueryInfluencers.effectiveBatchSize( entityDescriptor ); return createBatchingIdEntityLoader( entityDescriptor, batchSize, factory ); } + else { + return new ReactiveSingleIdEntityLoaderStandardImpl<>( entityDescriptor, loadQueryInfluencers ); + } } + } - return new ReactiveSingleIdEntityLoaderStandardImpl<>( entityDescriptor, new LoadQueryInfluencers( factory ) ); + private static NamedQueryMemento getNamedQueryMemento( + PersistentClass bootDescriptor, + RuntimeModelCreationContext creationContext, + SessionFactoryImplementor factory, + String entityName) { + final NamedQueryMemento namedQueryMemento = + factory.getQueryEngine().getNamedObjectRepository() + .resolve(factory, creationContext.getBootModel(), bootDescriptor.getLoaderName() ); + if ( namedQueryMemento == null ) { + throw new IllegalArgumentException( "Could not resolve named query '" + bootDescriptor.getLoaderName() + + "' for loading entity '" + entityName + "'" ); + } + return namedQueryMemento; } - private static ReactiveSingleIdEntityLoader createBatchingIdEntityLoader( + private static ReactiveSingleIdEntityLoader createBatchingIdEntityLoader( EntityMappingType entityDescriptor, int domainBatchSize, SessionFactoryImplementor factory) { - return (ReactiveSingleIdEntityLoader) factory.getServiceRegistry() - .getService( BatchLoaderFactory.class ) - .createEntityBatchLoader( domainBatchSize, entityDescriptor, factory ); + final EntityBatchLoader batchLoader = + factory.getServiceRegistry().requireService( BatchLoaderFactory.class ) + .createEntityBatchLoader( domainBatchSize, entityDescriptor, factory ); + return (ReactiveSingleIdEntityLoader) batchLoader; } public CompletionStage processInsertGeneratedProperties( @@ -236,7 +249,7 @@ protected ReactiveSingleUniqueKeyEntityLoader getReactiveUniqueKeyLoader ); } - public CompletionStage load( + public CompletionStage load( EntityPersister persister, Object id, Object optionalObject, @@ -255,7 +268,7 @@ public Generator reactive(Generator generator) { return generator instanceof IdentityGenerator ? new ReactiveIdentityGenerator() : generator; } - public CompletionStage loadEntityIdByNaturalId( + public CompletionStage loadEntityIdByNaturalId( Object[] orderedNaturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) { if ( LOG.isTraceEnabled() ) { LOG.tracef( "Resolving natural-id [%s] to id : %s ", @@ -264,7 +277,7 @@ public CompletionStage loadEntityIdByNaturalId( ); } - return ( (ReactiveNaturalIdLoader) entityDescriptor.getNaturalIdLoader() ) + return ( (ReactiveNaturalIdLoader) entityDescriptor.getNaturalIdLoader() ) .resolveNaturalIdToId( orderedNaturalIdValues, session ); } @@ -323,13 +336,15 @@ public AttributeMapping buildPluralAttributeMapping( } public EntityIdentifierMapping convertEntityIdentifierMapping(EntityIdentifierMapping entityIdentifierMapping) { - if ( entityIdentifierMapping instanceof NonAggregatedIdentifierMappingImpl ) { - return new ReactiveNonAggregatedIdentifierMappingImpl( (NonAggregatedIdentifierMappingImpl) entityIdentifierMapping ); + if ( entityIdentifierMapping instanceof NonAggregatedIdentifierMappingImpl nonAggregatedIdentifierMapping ) { + return new ReactiveNonAggregatedIdentifierMappingImpl(nonAggregatedIdentifierMapping); + } + else if ( entityIdentifierMapping instanceof EmbeddedIdentifierMappingImpl embeddedIdentifierMapping ) { + return new ReactiveEmbeddedIdentifierMappingImpl(embeddedIdentifierMapping); } - if ( entityIdentifierMapping instanceof EmbeddedIdentifierMappingImpl ) { - return new ReactiveEmbeddedIdentifierMappingImpl( (EmbeddedIdentifierMappingImpl) entityIdentifierMapping ); + else { + return entityIdentifierMapping; } - return entityIdentifierMapping; } private static class ReactiveNonAggregatedIdentifierMappingImpl extends NonAggregatedIdentifierMappingImpl { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java index 0a36d048d..16d6237f2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveEntityPersister.java @@ -12,7 +12,6 @@ import org.hibernate.LockOptions; import org.hibernate.bytecode.BytecodeLogging; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.spi.EventSource; import org.hibernate.generator.values.GeneratedValues; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; import org.hibernate.persister.entity.EntityPersister; @@ -92,40 +91,40 @@ CompletionStage reactiveLock( CompletionStage> reactiveMultiLoad( K[] ids, - EventSource session, + SharedSessionContractImplementor session, MultiIdLoadOptions loadOptions); - CompletionStage reactiveLoad( + CompletionStage reactiveLoad( Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session); - CompletionStage reactiveLoad( + CompletionStage reactiveLoad( Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session); - CompletionStage reactiveLoad( + CompletionStage reactiveLoad( Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly); - CompletionStage reactiveLoadByUniqueKey( + CompletionStage reactiveLoadByUniqueKey( String propertyName, Object uniqueKey, SharedSessionContractImplementor session); - CompletionStage reactiveLoadByUniqueKey( + CompletionStage reactiveLoadByUniqueKey( String propertyName, Object uniqueKey, Boolean readOnly, SharedSessionContractImplementor session); - CompletionStage reactiveLoadEntityIdByNaturalId( + CompletionStage reactiveLoadEntityIdByNaturalId( Object[] naturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java index b87ba6910..0182ef403 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java @@ -17,7 +17,6 @@ import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.spi.EventSource; import org.hibernate.generator.Generator; import org.hibernate.generator.values.GeneratedValues; import org.hibernate.loader.ast.spi.MultiIdEntityLoader; @@ -83,7 +82,7 @@ protected SingleIdEntityLoader buildSingleIdEntityLoader() { } @Override - protected MultiIdEntityLoader buildMultiIdLoader() { + protected MultiIdEntityLoader buildMultiIdLoader() { return reactiveDelegate.buildMultiIdEntityLoader(); } @@ -239,7 +238,7 @@ public CompletionStage mergeReactive( } @Override - public CompletionStage> reactiveMultiLoad(K[] ids, EventSource session, MultiIdLoadOptions loadOptions) { + public CompletionStage> reactiveMultiLoad(K[] ids, SharedSessionContractImplementor session, MultiIdLoadOptions loadOptions) { return reactiveDelegate.multiLoad( ids, session, loadOptions ); } @@ -313,7 +312,7 @@ protected Object initializeLazyPropertiesFromDatastore(Object entity, Object id, } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) { return reactiveLoad( id, optionalObject, new LockOptions().setLockMode( lockMode ), session ); } @@ -323,7 +322,7 @@ public Object load(Object id, Object optionalObject, LockOptions lockOptions, Sh } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session) { return doReactiveLoad( id, optionalObject, lockOptions, null, session ); } @@ -333,11 +332,11 @@ public Object load(Object id, Object optionalObject, LockOptions lockOptions, Sh } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly) { return doReactiveLoad( id, optionalObject, lockOptions, readOnly, session ); } - private CompletionStage doReactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { + private CompletionStage doReactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { return reactiveDelegate.load( this, id, optionalObject, lockOptions, readOnly, session ); } @@ -371,7 +370,7 @@ public CompletionStage reactiveLoadByUniqueKey(String propertyName, Obje * @see AbstractEntityPersister#loadEntityIdByNaturalId(Object[], LockOptions, SharedSessionContractImplementor) */ @Override - public CompletionStage reactiveLoadEntityIdByNaturalId(Object[] orderedNaturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoadEntityIdByNaturalId(Object[] orderedNaturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) { verifyHasNaturalId(); return reactiveDelegate.loadEntityIdByNaturalId( orderedNaturalIdValues, lockOptions, session ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java index 381a83b78..3006a0eae 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveSingleTableEntityPersister.java @@ -18,7 +18,6 @@ import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.spi.EventSource; import org.hibernate.generator.Generator; import org.hibernate.generator.values.GeneratedValues; import org.hibernate.generator.values.GeneratedValuesMutationDelegate; @@ -70,7 +69,7 @@ public class ReactiveSingleTableEntityPersister extends SingleTableEntityPersist private static final Log LOG = make( Log.class, lookup() ); - private ReactiveAbstractPersisterDelegate reactiveDelegate; + private final ReactiveAbstractPersisterDelegate reactiveDelegate; public ReactiveSingleTableEntityPersister( final PersistentClass persistentClass, @@ -102,7 +101,7 @@ protected SingleIdEntityLoader buildSingleIdEntityLoader() { } @Override - protected MultiIdEntityLoader buildMultiIdLoader() { + protected MultiIdEntityLoader buildMultiIdLoader() { return reactiveDelegate.buildMultiIdEntityLoader(); } @@ -302,13 +301,13 @@ public CompletionStage reactiveProcessUpdateGenerated(Object id, Object en * @see AbstractEntityPersister#loadEntityIdByNaturalId(Object[], LockOptions, SharedSessionContractImplementor) */ @Override - public CompletionStage reactiveLoadEntityIdByNaturalId(Object[] orderedNaturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoadEntityIdByNaturalId(Object[] orderedNaturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) { verifyHasNaturalId(); return reactiveDelegate.loadEntityIdByNaturalId( orderedNaturalIdValues, lockOptions, session ); } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) { return reactiveLoad( id, optionalObject, new LockOptions().setLockMode( lockMode ), session ); } @@ -318,7 +317,7 @@ public Object load(Object id, Object optionalObject, LockOptions lockOptions, Sh } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session) { return doReactiveLoad( id, optionalObject, lockOptions, null, session ); } @@ -328,11 +327,11 @@ public Object load(Object id, Object optionalObject, LockOptions lockOptions, Sh } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly) { return doReactiveLoad( id, optionalObject, lockOptions, readOnly, session ); } - private CompletionStage doReactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { + private CompletionStage doReactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { return reactiveDelegate.load( this, id, optionalObject, lockOptions, readOnly, session ); } @@ -397,7 +396,7 @@ public CompletionStage mergeReactive( } @Override - public CompletionStage> reactiveMultiLoad(K[] ids, EventSource session, MultiIdLoadOptions loadOptions) { + public CompletionStage> reactiveMultiLoad(K[] ids, SharedSessionContractImplementor session, MultiIdLoadOptions loadOptions) { return reactiveDelegate.multiLoad( ids, session, loadOptions ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java index cb7995acb..52871e30f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveUnionSubclassEntityPersister.java @@ -19,7 +19,6 @@ import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.spi.EventSource; import org.hibernate.generator.Generator; import org.hibernate.generator.values.GeneratedValues; import org.hibernate.id.IdentityGenerator; @@ -83,7 +82,7 @@ protected SingleIdEntityLoader buildSingleIdEntityLoader() { } @Override - protected MultiIdEntityLoader buildMultiIdLoader() { + protected MultiIdEntityLoader buildMultiIdLoader() { return reactiveDelegate.buildMultiIdEntityLoader(); } @@ -149,14 +148,6 @@ public NaturalIdMapping generateNaturalIdMapping(MappingModelCreationProcess cre return ReactiveAbstractEntityPersister.super.generateNaturalIdMapping(creationProcess, bootEntityDescriptor); } - - @Override - protected void validateGenerator() { - if ( super.getGenerator() instanceof IdentityGenerator ) { - throw new MappingException( "Cannot use identity column key generation with mapping for: " + getEntityName() ); - } - } - @Override protected InsertCoordinator buildInsertCoordinator() { return ReactiveCoordinatorFactory.buildInsertCoordinator( this, getFactory() ); @@ -181,6 +172,13 @@ public DomainResult createDomainResult( return reactiveDelegate.createDomainResult( this, navigablePath, tableGroup, resultVariable, creationState ); } + @Override + protected void validateGenerator() { + if ( super.getGenerator() instanceof IdentityGenerator) { + throw new MappingException( "Cannot use identity column key generation with mapping for: " + getEntityName() ); + } + } + @Override public Generator getGenerator() throws HibernateException { return reactiveDelegate.reactive( super.getGenerator() ); @@ -280,7 +278,7 @@ protected Object initializeLazyPropertiesFromDatastore(Object entity, Object id, } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) { return reactiveLoad( id, optionalObject, new LockOptions().setLockMode( lockMode ), session ); } @@ -290,7 +288,7 @@ public Object load(Object id, Object optionalObject, LockOptions lockOptions, Sh } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session) { return doReactiveLoad( id, optionalObject, lockOptions, null, session ); } @@ -300,11 +298,11 @@ public Object load(Object id, Object optionalObject, LockOptions lockOptions, Sh } @Override - public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly) { + public CompletionStage reactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly) { return doReactiveLoad( id, optionalObject, lockOptions, readOnly, session ); } - private CompletionStage doReactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { + private CompletionStage doReactiveLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) { return reactiveDelegate.load( this, id, optionalObject, lockOptions, readOnly, session ); } @@ -365,7 +363,7 @@ public CompletionStage mergeReactive( } @Override - public CompletionStage> reactiveMultiLoad(K[] ids, EventSource session, MultiIdLoadOptions loadOptions) { + public CompletionStage> reactiveMultiLoad(K[] ids, SharedSessionContractImplementor session, MultiIdLoadOptions loadOptions) { return reactiveDelegate.multiLoad( ids, session, loadOptions ); } @@ -373,7 +371,7 @@ public CompletionStage> reactiveMultiLoad(K[] ids, EventSo * @see AbstractEntityPersister#loadEntityIdByNaturalId(Object[], LockOptions, SharedSessionContractImplementor) */ @Override - public CompletionStage reactiveLoadEntityIdByNaturalId(Object[] orderedNaturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) { + public CompletionStage reactiveLoadEntityIdByNaturalId(Object[] orderedNaturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) { verifyHasNaturalId(); return reactiveDelegate.loadEntityIdByNaturalId( orderedNaturalIdValues, lockOptions, session ); } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveSelectionQuery.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveSelectionQuery.java index 6c35d9260..2ee7a051e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveSelectionQuery.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/ReactiveSelectionQuery.java @@ -5,15 +5,6 @@ */ package org.hibernate.reactive.query; -import java.time.Instant; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletionStage; - import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockMode; @@ -22,7 +13,6 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.query.BindableType; import org.hibernate.query.CommonQueryContract; -import org.hibernate.query.Order; import org.hibernate.query.QueryParameter; import jakarta.persistence.CacheRetrieveMode; @@ -31,6 +21,14 @@ import jakarta.persistence.LockModeType; import jakarta.persistence.Parameter; import jakarta.persistence.TemporalType; +import java.time.Instant; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletionStage; /** * @see org.hibernate.query.SelectionQuery @@ -123,10 +121,6 @@ default CompletionStage> getReactiveResultList() { void applyGraph(RootGraphImplementor graph, GraphSemantic semantic); - ReactiveSelectionQuery setOrder(List> orderList); - - ReactiveSelectionQuery setOrder(Order order); - ReactiveSelectionQuery enableFetchProfile(String profileName); @Override diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java index ef2d70afe..9fd78d104 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/internal/ReactiveNamedObjectRepositoryImpl.java @@ -5,6 +5,7 @@ */ package org.hibernate.reactive.query.internal; +import jakarta.persistence.TypedQuery; import java.util.Map; import java.util.function.Consumer; @@ -48,6 +49,11 @@ public void registerNamedQuery(String name, Query query) { delegate.registerNamedQuery( name, query ); } + @Override + public TypedQueryReference registerNamedQuery(String name, TypedQuery query) { + return delegate.registerNamedQuery( name, query ); + } + @Override public void visitSqmQueryMementos(Consumer> action) { delegate.visitSqmQueryMementos( action ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java index 1137e0a62..9c2647b8f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/spi/ReactiveAbstractSelectionQuery.java @@ -30,7 +30,7 @@ import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.SqmInterpretationsKey; -import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKeySource; +import org.hibernate.query.sqm.spi.InterpretationsKeySource; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java index ac8f4e9b4..afaf43e41 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/internal/ReactiveNativeQueryImpl.java @@ -28,7 +28,6 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.query.BindableType; -import org.hibernate.query.Order; import org.hibernate.query.QueryParameter; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; @@ -528,18 +527,6 @@ public ReactiveNativeQueryImpl setLockMode(String alias, LockMode lockMode) { return this; } - @Override - public ReactiveNativeQueryImpl setOrder(List> orders) { - super.setOrder( orders ); - return this; - } - - @Override - public ReactiveNativeQueryImpl setOrder(Order order) { - super.setOrder( order ); - return this; - } - @Override public ReactiveNativeQueryImpl setComment(String comment) { super.setComment( comment ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/ReactiveSqmSelectionQuery.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/ReactiveSqmSelectionQuery.java index 1d897653f..92d00b305 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/ReactiveSqmSelectionQuery.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/ReactiveSqmSelectionQuery.java @@ -9,13 +9,11 @@ import java.util.Calendar; import java.util.Collection; import java.util.Date; -import java.util.List; import java.util.Map; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.query.BindableType; -import org.hibernate.query.Order; import org.hibernate.query.QueryParameter; import org.hibernate.query.spi.SqmQuery; import org.hibernate.reactive.query.ReactiveSelectionQuery; @@ -169,12 +167,6 @@

ReactiveSqmSelectionQuery setParameterList( @Override ReactiveSqmSelectionQuery setTimeout(int timeout); - @Override - ReactiveSqmSelectionQuery setOrder(List> orderList); - - @Override - ReactiveSqmSelectionQuery setOrder(Order order); - @Override ReactiveSqmSelectionQuery setFetchSize(int fetchSize); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java index 096196576..61f0d39c6 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveQuerySqmImpl.java @@ -34,7 +34,6 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.BindableType; import org.hibernate.query.IllegalQueryOperationException; -import org.hibernate.query.Order; import org.hibernate.query.QueryParameter; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; @@ -478,18 +477,6 @@ public ReactiveQuerySqmImpl setLockMode(String alias, LockMode lockMode) { return this; } - @Override - public ReactiveQuerySqmImpl setOrder(List> orders) { - super.setOrder( orders ); - return this; - } - - @Override - public ReactiveQuerySqmImpl setOrder(Order order) { - super.setOrder( order ); - return this; - } - @Override public ReactiveQuerySqmImpl setTupleTransformer(TupleTransformer transformer) { throw new UnsupportedOperationException(); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java index bca5e2a65..9249b0544 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/internal/ReactiveSqmSelectionQueryImpl.java @@ -6,17 +6,6 @@ package org.hibernate.reactive.query.sqm.internal; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletionStage; -import java.util.stream.Stream; - import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.HibernateException; @@ -26,7 +15,6 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.query.BindableType; -import org.hibernate.query.Order; import org.hibernate.query.QueryLogging; import org.hibernate.query.QueryParameter; import org.hibernate.query.internal.DelegatingDomainQueryExecutionContext; @@ -47,6 +35,16 @@ import jakarta.persistence.LockModeType; import jakarta.persistence.Parameter; import jakarta.persistence.TemporalType; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletionStage; +import java.util.stream.Stream; import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions; @@ -258,18 +256,6 @@ public ReactiveSqmSelectionQueryImpl setFollowOnLocking(boolean enable) { return this; } - @Override - public ReactiveSqmSelectionQueryImpl setOrder(List> orders) { - super.setOrder( orders ); - return this; - } - - @Override - public ReactiveSqmSelectionQueryImpl setOrder(Order order) { - super.setOrder( order ); - return this; - } - @Override public ReactiveSqmSelectionQueryImpl setFetchSize(int fetchSize) { super.setFetchSize( fetchSize ); 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 a3b667fea..c9a7cc11b 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 @@ -5,6 +5,7 @@ */ package org.hibernate.reactive.session; +import jakarta.persistence.TypedQueryReference; import java.util.concurrent.CompletionStage; import org.hibernate.Incubating; @@ -53,6 +54,8 @@ public interface ReactiveQueryProducer extends ReactiveConnectionSupplier { ReactiveQuery createReactiveQuery(String queryString); + ReactiveQuery createReactiveQuery(TypedQueryReference typedQueryReference); + ReactiveQuery createReactiveQuery(CriteriaQuery criteriaQuery); ReactiveQuery createReactiveQuery(String queryString, Class resultType); 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 72157e46e..f3cefc7dc 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 @@ -5,6 +5,8 @@ */ package org.hibernate.reactive.session.impl; +import jakarta.persistence.TypedQueryReference; +import jakarta.persistence.criteria.CommonAbstractCriteria; import java.lang.invoke.MethodHandles; import java.util.List; import java.util.Map; @@ -76,6 +78,8 @@ import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.query.hql.spi.SqmQueryImplementor; import org.hibernate.query.named.NamedResultSetMappingMemento; +import org.hibernate.query.specification.internal.MutationSpecificationImpl; +import org.hibernate.query.specification.internal.SelectionSpecificationImpl; import org.hibernate.query.spi.HqlInterpretation; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.sql.spi.NamedNativeQueryMemento; @@ -357,6 +361,33 @@ protected ReactiveQueryImplementor createReactiveCriteriaQuery(SqmStateme return query; } + @Override + public ReactiveQuery createReactiveQuery(TypedQueryReference typedQueryReference) { + checksBeforeQueryCreation(); + if ( typedQueryReference instanceof SelectionSpecificationImpl specification ) { + final CriteriaQuery query = specification.buildCriteria( getCriteriaBuilder() ); + return new ReactiveQuerySqmImpl<>( (SqmStatement) query, specification.getResultType(), this ); + } + if ( typedQueryReference instanceof MutationSpecificationImpl specification ) { + final CommonAbstractCriteria query = specification.buildCriteria( getCriteriaBuilder() ); + // Workaround for ORM, can be remove when this issue is solved: https://hibernate.atlassian.net/browse/HHH-19386 + Class type = specification.getResultType() == Void.class + ? null + : (Class) specification.getResultType(); + return new ReactiveQuerySqmImpl<>( (SqmStatement) query, type, this ); + } + @SuppressWarnings("unchecked") + // this cast is fine because of all our impls of TypedQueryReference return Class + final Class resultType = (Class) typedQueryReference.getResultType(); + ReactiveQueryImplementor query = (ReactiveQueryImplementor) buildNamedQuery( + typedQueryReference.getName(), + memento -> createSqmQueryImplementor( resultType, memento ), + memento -> createNativeQueryImplementor( resultType, memento ) + ); + typedQueryReference.getHints().forEach( query::setHint ); + return query; + } + @Override public ReactiveQuery createReactiveQuery(String queryString) { return createReactiveQuery( queryString, null ); @@ -1250,10 +1281,6 @@ private ReactiveEntityPersister entityPersister(Class entityClass) { return (ReactiveEntityPersister) getFactory().getMappingMetamodel().getEntityDescriptor( entityClass ); } - private EntityPersister requireEntityPersister(Class entityClass) { - return getFactory().getMappingMetamodel().getEntityDescriptor( entityClass ); - } - private CompletionStage fireReactiveLoad(LoadEvent event, LoadEventListener.LoadType loadType) { checkOpenOrWaitingForAutoClose(); @@ -1283,10 +1310,6 @@ public void checkTransactionNeededForUpdateOperation(String exceptionMessage) { //no-op because we don't support transactions } - private Boolean getReadOnlyFromLoadQueryInfluencers() { - return getLoadQueryInfluencers().getReadOnly(); - } - private class ReactiveIdentifierLoadAccessImpl { private final EntityPersister entityPersister; @@ -1435,7 +1458,7 @@ protected final CompletionStage doLoad(Object id, LoadEventListener.LoadType } private class ReactiveMultiIdentifierLoadAccessImpl implements MultiIdLoadOptions { - private final EntityPersister entityPersister; + private final ReactiveEntityPersister entityPersister; private LockOptions lockOptions; private CacheMode cacheMode; @@ -1450,7 +1473,7 @@ private class ReactiveMultiIdentifierLoadAccessImpl implements MultiIdLoadOpt private boolean readOnly; public ReactiveMultiIdentifierLoadAccessImpl(EntityPersister entityPersister) { - this.entityPersister = entityPersister; + this.entityPersister = (ReactiveEntityPersister) entityPersister; } @Override @@ -1489,12 +1512,7 @@ public Integer getBatchSize() { } public ReactiveMultiIdentifierLoadAccessImpl withBatchSize(int batchSize) { - if ( batchSize < 1 ) { - this.batchSize = null; - } - else { - this.batchSize = batchSize; - } + this.batchSize = batchSize < 1 ? null : batchSize; return this; } @@ -1537,8 +1555,11 @@ public CompletionStage> multiLoad(Object... ids) { Object[] sids = new Object[ids.length]; System.arraycopy( ids, 0, sids, 0, ids.length ); - return perform( () -> (CompletionStage) ( (ReactiveEntityPersister) entityPersister ) - .reactiveMultiLoad( sids, ReactiveSessionImpl.this, this ) ); + return perform( () -> { + final CompletionStage> stage = + entityPersister.reactiveMultiLoad( sids, ReactiveSessionImpl.this, this ); + return (CompletionStage>) stage; + }); } public CompletionStage> perform(Supplier>> executor) { @@ -1572,12 +1593,6 @@ public CompletionStage> perform(Supplier>> execu } } ); } - - @SuppressWarnings("unchecked") - public CompletionStage> multiLoad(List ids) { - return perform( () -> (CompletionStage>) - entityPersister.multiLoad( ids.toArray( new Object[0] ), ReactiveSessionImpl.this, this ) ); - } } private class NaturalIdLoadAccessImpl { 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 2d3efe4f5..5079f0315 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 @@ -5,12 +5,6 @@ */ package org.hibernate.reactive.session.impl; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.function.Supplier; - import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -29,10 +23,6 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.spi.PostInsertEvent; -import org.hibernate.event.spi.PostInsertEventListener; -import org.hibernate.event.spi.PreInsertEvent; -import org.hibernate.event.spi.PreInsertEventListener; import org.hibernate.generator.BeforeExecutionGenerator; import org.hibernate.generator.Generator; import org.hibernate.graph.GraphSemantic; @@ -50,10 +40,10 @@ import org.hibernate.query.IllegalMutationQueryException; import org.hibernate.query.UnknownNamedQueryException; import org.hibernate.query.criteria.JpaCriteriaInsert; -import org.hibernate.query.criteria.JpaCriteriaQuery; -import org.hibernate.query.criteria.JpaRoot; import org.hibernate.query.hql.spi.SqmQueryImplementor; import org.hibernate.query.named.NamedResultSetMappingMemento; +import org.hibernate.query.specification.internal.MutationSpecificationImpl; +import org.hibernate.query.specification.internal.SelectionSpecificationImpl; import org.hibernate.query.spi.HqlInterpretation; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor; @@ -89,9 +79,15 @@ import jakarta.persistence.EntityGraph; import jakarta.persistence.Tuple; +import jakarta.persistence.TypedQueryReference; +import jakarta.persistence.criteria.CommonAbstractCriteria; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Supplier; import static java.lang.Boolean.TRUE; import static java.lang.invoke.MethodHandles.lookup; @@ -223,24 +219,17 @@ public CompletionStage> reactiveGet(Class entityClass, Object... } } - final EntityPersister persister = getEntityPersister( entityClass.getName() ); + Object[] sids = new Object[ids.length]; + System.arraycopy( ids, 0, sids, 0, ids.length ); - final JpaCriteriaQuery query = getCriteriaBuilder().createQuery(entityClass); - final JpaRoot from = query.from(entityClass); - query.where( from.get( persister.getIdentifierPropertyName() ).in(ids) ); - return createReactiveQuery(query).getReactiveResultList() - .thenApply( resultList -> { - final List idList = new ArrayList<>( resultList.size() ); - for (T entity : resultList) { - idList.add( persister.getIdentifier(entity, this) ); - } - final List list = new ArrayList<>( ids.length ); - for (Object id : ids) { - final int pos = idList.indexOf(id); - list.add( pos < 0 ? null : resultList.get(pos) ); + return getEntityPersister( entityClass.getName() ) + .reactiveMultiLoad( sids, this, StatelessSessionImpl.MULTI_ID_LOAD_OPTIONS ) + .whenComplete( (v, e) -> { + if ( getPersistenceContext().isLoadFinished() ) { + getPersistenceContext().clear(); } - return list; - }); + } ) + .thenApply( objects -> (List) objects ); } @Override @@ -349,29 +338,6 @@ private CompletionStage reactiveInsert(Object entity, ReactiveEntityPersis } } - private boolean firePreInsert(Object entity, Object id, Object[] state, EntityPersister persister) { - if ( getFactory().getEventListenerGroups().eventListenerGroup_PRE_INSERT.isEmpty() ) { - return false; - } - else { - boolean veto = false; - final PreInsertEvent event = new PreInsertEvent( entity, id, state, persister, null ); - for ( PreInsertEventListener listener : getFactory().getEventListenerGroups().eventListenerGroup_PRE_INSERT.listeners() ) { - veto |= listener.onPreInsert( event ); - } - return veto; - } - } - - private void firePostInsert(Object entity, Object id, Object[] state, EntityPersister persister) { - if ( !getFactory().getEventListenerGroups().eventListenerGroup_POST_INSERT.isEmpty() ) { - final PostInsertEvent event = new PostInsertEvent( entity, id, state, persister, null ); - for ( PostInsertEventListener listener : getFactory().getEventListenerGroups().eventListenerGroup_POST_INSERT.listeners() ) { - listener.onPostInsert( event ); - } - } - } - private CompletionStage generateId(EntityPersister persister, Object entity, Generator generator) { if ( generator.generatesOnInsert() ) { if ( generator instanceof ReactiveIdentifierGenerator reactiveGenerator ) { @@ -485,9 +451,9 @@ public CompletionStage reactiveRefresh(String entityName, Object entity, L } ); } - private CompletionStage fromInternalFetchProfile( + private CompletionStage fromInternalFetchProfile( CascadingFetchProfile cascadingFetchProfile, - Supplier> supplier) { + Supplier> supplier) { CascadingFetchProfile previous = getLoadQueryInfluencers().getEnabledCascadingFetchProfile(); return voidFuture() .thenCompose( v -> { @@ -830,6 +796,33 @@ public RootGraphImplementor getEntityGraph(Class entity, String name) return (RootGraphImplementor) entityGraph; } + @Override + public ReactiveQuery createReactiveQuery(TypedQueryReference typedQueryReference) { + checksBeforeQueryCreation(); + if ( typedQueryReference instanceof SelectionSpecificationImpl specification ) { + final CriteriaQuery query = specification.buildCriteria( getCriteriaBuilder() ); + return new ReactiveQuerySqmImpl<>( (SqmStatement) query, specification.getResultType(), this ); + } + if ( typedQueryReference instanceof MutationSpecificationImpl specification ) { + final CommonAbstractCriteria query = specification.buildCriteria( getCriteriaBuilder() ); + // Workaround for ORM, can be remove when this issue is solved: https://hibernate.atlassian.net/browse/HHH-19386 + Class type = (Class) specification.getResultType() == Void.class + ? null + : (Class) specification.getResultType(); + return new ReactiveQuerySqmImpl<>( (SqmStatement) query, type, this ); + } + @SuppressWarnings("unchecked") + // this cast is fine because of all our impls of TypedQueryReference return Class + final Class resultType = (Class) typedQueryReference.getResultType(); + ReactiveQueryImplementor query = (ReactiveQueryImplementor) buildNamedQuery( + typedQueryReference.getName(), + memento -> createSqmQueryImplementor( resultType, memento ), + memento -> createNativeQueryImplementor( resultType, memento ) + ); + typedQueryReference.getHints().forEach( query::setHint ); + return query; + } + @Override public ReactiveSqmQueryImplementor createReactiveQuery(String queryString) { return createReactiveQuery( queryString, null ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java index 64c5b3af3..5993d1893 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/exec/internal/StandardReactiveSelectExecutor.java @@ -412,14 +412,17 @@ public CompletionStage resolveJdbcValuesSource( } } + /** + * Copied from Hibernate ORM + */ private static CacheMode resolveCacheMode(ExecutionContext executionContext) { final QueryOptions queryOptions = executionContext.getQueryOptions(); final SharedSessionContract session = executionContext.getSession(); - return coalesceSuppliedValues( - () -> queryOptions == null ? null : queryOptions.getCacheMode(), - session::getCacheMode, - () -> CacheMode.NORMAL - ); + return coalesceSuppliedValues( + () -> queryOptions == null ? null : queryOptions.getCacheMode(), + session::getCacheMode, + () -> CacheMode.NORMAL + ); } /** 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 601b17c11..1920acc95 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 @@ -5,6 +5,7 @@ */ package org.hibernate.reactive.stage; +import jakarta.persistence.TypedQueryReference; import java.lang.invoke.MethodHandles; import java.util.List; import java.util.concurrent.CompletionStage; @@ -24,8 +25,8 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.jpa.internal.util.FlushModeTypeHelper; import org.hibernate.proxy.HibernateProxy; -import org.hibernate.query.Order; import org.hibernate.query.Page; +import org.hibernate.query.Query; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.reactive.common.AffectedEntities; @@ -360,37 +361,6 @@ default SelectionQuery setLockMode(String alias, LockModeType lockModeType) { return setLockMode( alias, convertToLockMode(lockModeType) ); } -// /** -// * Set the {@link LockOptions} to use for the whole query. -// * -// * @see org.hibernate.query.Query#setLockOptions(LockOptions) -// */ -// Query setLockOptions(LockOptions lockOptions); - - /** - * If the result type of this query is an entity class, add one or more - * {@linkplain Order rules} for ordering the query results. - * - * @param orderList one or more instances of {@link Order} - * - * @see Order - * - * @see org.hibernate.query.Query#setOrder(List) - */ - SelectionQuery setOrder(List> orderList); - - /** - * If the result type of this query is an entity class, add a - * {@linkplain Order rule} for ordering the query results. - * - * @param order an instance of {@link Order} - * - * @see Order - * - * @see org.hibernate.query.Query#setOrder(Order) - */ - SelectionQuery setOrder(Order order); - /** * Set the {@link EntityGraph} that will be used as a fetch plan for * the root entity returned by this query. @@ -885,17 +855,6 @@ default CompletionStage lock(Object entity, LockModeType lockModeType) { return lock( entity, convertToLockMode(lockModeType) ); } -// /** -// * Obtain the specified lock level upon the given object, with the given -// * {@link LockOptions}. -// * -// * @param entity a managed persistent instance -// * @param lockOptions the requested {@link LockOptions} -// * -// * @throws IllegalArgumentException if the given instance is not managed -// */ -// CompletionStage lock(Object entity, LockOptions lockOptions); - /** * Force this session to flush asynchronously. Must be called at the * end of a unit of work, before committing the transaction and closing @@ -1028,6 +987,22 @@ default CompletionStage lock(Object entity, LockModeType lockModeType) { */ MutationQuery createMutationQuery(JpaCriteriaInsert insert); + /** + * Create a typed {@link Query} instance for the given typed query reference. + * + * @param typedQueryReference the type query reference + * + * @return The {@link Query} instance for execution + * + * @throws IllegalArgumentException if a query has not been + * defined with the name of the typed query reference or if + * the query result is found to not be assignable to + * result class of the typed query reference + * + * @see org.hibernate.query.QueryProducer#createQuery(TypedQueryReference) + */ + Query createQuery(TypedQueryReference typedQueryReference); + /** * 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 @@ -1680,6 +1655,22 @@ default CompletionStage get(Class entityClass, Object id, LockModeType @Deprecated Query createQuery(String queryString); + /** + * Create a typed {@link Query} instance for the given typed query reference. + * + * @param typedQueryReference the type query reference + * + * @return The {@link Query} instance for execution + * + * @throws IllegalArgumentException if a query has not been + * defined with the name of the typed query reference or if + * the query result is found to not be assignable to + * result class of the typed query reference + * + * @see org.hibernate.query.QueryProducer#createQuery(TypedQueryReference) + */ + Query createQuery(TypedQueryReference typedQueryReference); + /** * Create an instance of {@link SelectionQuery} for the given HQL/JPQL * query string and query result type. diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageQueryImpl.java index fb022c499..df0c04c5a 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageQueryImpl.java @@ -13,7 +13,6 @@ import org.hibernate.LockMode; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.query.Order; import org.hibernate.query.Page; import org.hibernate.reactive.query.ReactiveQuery; import org.hibernate.reactive.stage.Stage; @@ -65,18 +64,6 @@ public Query setLockMode(LockMode lockMode) { return this; } - @Override - public Stage.SelectionQuery setOrder(List> orders) { - delegate.setOrder( orders ); - return this; - } - - @Override - public Stage.SelectionQuery setOrder(Order order) { - delegate.setOrder( (List>) order ); - return this; - } - @Override public Query setPlan(EntityGraph entityGraph) { delegate.applyGraph( (RootGraphImplementor) entityGraph, GraphSemantic.FETCH ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java index eaf1c9a53..71beb5df3 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java @@ -13,7 +13,6 @@ import org.hibernate.LockMode; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.spi.RootGraphImplementor; -import org.hibernate.query.Order; import org.hibernate.query.Page; import org.hibernate.reactive.query.ReactiveSelectionQuery; import org.hibernate.reactive.stage.Stage.SelectionQuery; @@ -194,18 +193,6 @@ public SelectionQuery setLockMode(String alias, LockMode lockMode) { return this; } - @Override - public SelectionQuery setOrder(List> orders) { - delegate.setOrder( orders ); - return this; - } - - @Override - public SelectionQuery setOrder(Order order) { - delegate.setOrder( order ); - return this; - } - @Override public SelectionQuery setParameter(String name, Object value) { delegate.setParameter( name, value ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java index 150c2ec96..dd25105f1 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java @@ -5,6 +5,7 @@ */ package org.hibernate.reactive.stage.impl; +import jakarta.persistence.TypedQueryReference; import java.lang.invoke.MethodHandles; import java.util.List; import java.util.concurrent.CompletionStage; @@ -26,6 +27,7 @@ import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.pool.ReactiveConnection; +import org.hibernate.reactive.query.ReactiveQuery; import org.hibernate.reactive.session.ReactiveConnectionSupplier; import org.hibernate.reactive.session.ReactiveQueryProducer; import org.hibernate.reactive.session.ReactiveSession; @@ -530,6 +532,12 @@ public EntityGraph createEntityGraph(Class rootType, String graphName) return delegate.createEntityGraph( rootType, graphName ); } + @Override + public Query createQuery(TypedQueryReference typedQueryReference) { + ReactiveQuery reactiveQuery = delegate.createReactiveQuery( typedQueryReference ); + return new StageQueryImpl<>( reactiveQuery ); + } + @Override @Deprecated public Query createQuery(String queryString) { return new StageQueryImpl<>( delegate.createReactiveQuery( queryString ) ); 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 c48a7eab8..425a0d363 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 @@ -10,6 +10,7 @@ import org.hibernate.query.criteria.JpaCriteriaInsert; import org.hibernate.reactive.common.ResultSetMapping; import org.hibernate.reactive.pool.ReactiveConnection; +import org.hibernate.reactive.query.ReactiveQuery; import org.hibernate.reactive.session.ReactiveStatelessSession; import org.hibernate.reactive.stage.Stage; import org.hibernate.reactive.stage.Stage.MutationQuery; @@ -17,6 +18,7 @@ import org.hibernate.reactive.stage.Stage.SelectionQuery; import jakarta.persistence.EntityGraph; +import jakarta.persistence.TypedQueryReference; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; @@ -289,6 +291,12 @@ public Query createQuery(String queryString) { return new StageQueryImpl<>( delegate.createReactiveQuery( queryString ) ); } + @Override + public Query createQuery(TypedQueryReference typedQueryReference) { + ReactiveQuery reactiveQuery = delegate.createReactiveQuery( typedQueryReference ); + return new StageQueryImpl<>( reactiveQuery ); + } + @Override public SelectionQuery createSelectionQuery(String queryString, Class resultType) { return new StageSelectionQueryImpl<>( delegate.createReactiveSelectionQuery( queryString, resultType ) ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveJsonArrayJdbcType.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveJsonArrayJdbcType.java index adc00ff79..81af936ba 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveJsonArrayJdbcType.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveJsonArrayJdbcType.java @@ -5,12 +5,6 @@ */ package org.hibernate.reactive.type.descriptor.jdbc; -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.hibernate.dialect.JsonHelper; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.type.SqlTypes; import org.hibernate.type.descriptor.ValueBinder; @@ -23,9 +17,14 @@ import org.hibernate.type.descriptor.jdbc.BasicExtractor; import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.JsonHelper; import org.hibernate.type.descriptor.jdbc.JsonJdbcType; import io.vertx.core.json.JsonArray; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; /** * @see org.hibernate.type.descriptor.jdbc.JsonArrayJdbcType diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveOracleArrayJdbcType.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveOracleArrayJdbcType.java index 52a9d9206..09000a9e0 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveOracleArrayJdbcType.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveOracleArrayJdbcType.java @@ -13,7 +13,8 @@ import org.hibernate.HibernateException; import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.OracleArrayJdbcType; + +import org.hibernate.dialect.type.OracleArrayJdbcType; import org.hibernate.reactive.adaptor.impl.ArrayAdaptor; import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.ValueBinder; @@ -30,7 +31,7 @@ import static java.sql.Types.ARRAY; /** - * @see org.hibernate.dialect.OracleArrayJdbcType + * @see org.hibernate.dialect.type.OracleArrayJdbcType */ public class ReactiveOracleArrayJdbcType extends OracleArrayJdbcType { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlArrayJdbcType.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlArrayJdbcType.java index 306e619b8..7f30d8d29 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlArrayJdbcType.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlArrayJdbcType.java @@ -5,12 +5,6 @@ */ package org.hibernate.reactive.type.descriptor.jdbc; -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.SQLXML; - -import org.hibernate.dialect.XmlHelper; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.WrapperOptions; @@ -18,6 +12,12 @@ import org.hibernate.type.descriptor.jdbc.BasicBinder; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.XmlArrayJdbcType; +import org.hibernate.type.descriptor.jdbc.XmlHelper; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.SQLXML; import static java.lang.invoke.MethodHandles.lookup; import static org.hibernate.reactive.logging.impl.LoggerFactory.make; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java index 3c3667aa3..a81840263 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/type/descriptor/jdbc/ReactiveXmlJdbcType.java @@ -5,20 +5,20 @@ */ package org.hibernate.reactive.type.descriptor.jdbc; -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.SQLXML; - -import org.hibernate.dialect.XmlHelper; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.BasicBinder; +import org.hibernate.type.descriptor.jdbc.XmlHelper; import org.hibernate.type.descriptor.jdbc.XmlJdbcType; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.SQLXML; + import static java.lang.invoke.MethodHandles.lookup; import static org.hibernate.reactive.logging.impl.LoggerFactory.make; diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OrderTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OrderTest.java deleted file mode 100644 index 48b73829f..000000000 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OrderTest.java +++ /dev/null @@ -1,345 +0,0 @@ -/* 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.metamodel.model.domain.EntityDomainType; -import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl; - -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.metamodel.SingularAttribute; - -import static java.util.concurrent.TimeUnit.MINUTES; -import static java.util.stream.Collectors.toList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.hibernate.query.Order.asc; -import static org.hibernate.query.Order.desc; - -@Timeout(value = 10, timeUnit = MINUTES) -public class OrderTest extends BaseReactiveTest { - final Book book1 = new Book( "9781932394153", "Hibernate in Action" ); - final Book book2 = new Book( "9781617290459", "Java Persistence with Hibernate" ); - - SingularAttribute isbn; - SingularAttribute title; - - @Override - protected Collection> annotatedEntities() { - return List.of( Book.class ); - } - - @BeforeEach - public void populateDB(VertxTestContext context) { - isbn = attribute( "isbn" ); - title = attribute( "title" ); - test( context, getSessionFactory().withTransaction( session -> session.persist( book1, book2 ) ) ); - } - - @Test - public void descPositionalColumnWithStage(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - // Not sure if it's a bug, but setOrder doesn't work if we use String.class - .createSelectionQuery( "select title from Book", Object[].class ) - .setOrder( desc( 1 ) ) - .getResultList() - .thenAccept( results -> assertThat( results ) - // Keep the title - .map( row -> row[0] ) - .containsExactly( book2.title, book1.title ) ) - ) ); - } - - @Test - public void descPositionalColumnWithMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - // Not sure if it's a bug, but setOrder doesn't work if we use String.class or Object.class - .createSelectionQuery( "select title from Book", Object[].class ) - .setOrder( desc( 1 ) ) - .getResultList() - .invoke( results -> assertThat( results ) - // Keep the title - .map( row -> row[0] ) - .containsExactly( book2.title, book1.title ) - ) - ) ); - } - - @Test - public void ascAttributeWithStage(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( asc( title ) ) - .getResultList() - .thenAccept( books -> assertThat( books ).containsExactly( book1, book2 ) ) - ) ); - } - - @Test - public void ascAttributeWithMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( asc( title ) ) - .getResultList() - .invoke( books -> assertThat( books ).containsExactly( book1, book2 ) ) - ) ); - } - - @Test - public void descAttributeWithStage(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( desc( title ) ) - .getResultList() - .thenAccept( books -> assertThat( books ).containsExactly( book2, book1 ) ) - ) ); - } - - @Test - public void descAttributeWithMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( desc( title ) ) - .getResultList() - .invoke( books -> assertThat( books ).containsExactly( book2, book1 ) ) - ) ); - } - - @Test - public void ascIdWithStage(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( asc( isbn ) ) - .getResultList() - .thenAccept( books -> assertThat( books ).containsExactly( book2, book1 ) ) - ) ); - } - - @Test - public void ascIdWithMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( asc( isbn ) ) - .getResultList() - .invoke( books -> assertThat( books ).containsExactly( book2, book1 ) ) - ) ); - } - - @Test - public void descIdWithStage(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( desc( isbn ) ) - .getResultList() - .thenAccept( books -> assertThat( books ).containsExactly( book1, book2 ) ) - ) ); - } - - @Test - public void descIdWithMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( desc( isbn ) ) - .getResultList() - .invoke( books -> assertThat( books ).containsExactly( book1, book2 ) ) - ) ); - } - - @Test - public void testAscDescBySelectElement(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "select isbn, title from Book", Object[].class ) - .setOrder( asc( 2 ) ) - .getResultList() - .thenAccept( list -> assertOrderByBookArray( list, book1, book2 ) ) - .thenCompose( v -> session - .createSelectionQuery( "select isbn, title from Book", Object[].class ) - .setOrder( desc( 2 ) ) - .getResultList() - .thenAccept( list -> assertOrderByBookArray( list, book2, book1 ) ) - ) - ) ); - } - - @Test - public void testAscDescBySelectElementMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "select isbn, title from Book", Object[].class ) - .setOrder( asc( 2 ) ) - .getResultList() - .invoke( list -> assertOrderByBookArray( list, book1, book2 ) ) - .chain( v -> session - .createSelectionQuery( "select isbn, title from Book", Object[].class ) - .setOrder( desc( 2 ) ) - .getResultList() - .invoke( list -> assertOrderByBookArray( list, book2, book1 ) ) - ) - ) ); - } - - @Test - public void testOrderWithList(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( List.of( asc( isbn ), desc( title ) ) ).getResultList() - .thenAccept( isbnAsc -> assertThat( isbnAsc ).containsExactly( book2, book1 ) ) - .thenCompose( v -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( List.of( desc( isbn ), desc( title ) ) ).getResultList() - .thenAccept( isbnDesc -> assertThat( isbnDesc ).containsExactly( book1, book2 ) ) - ) - ) ); - } - - @Test - public void testOrderWithListMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( List.of( asc( isbn ), desc( title ) ) ).getResultList() - .invoke( isbnAsc -> assertThat( isbnAsc ).containsExactly( book2, book1 ) ) - .chain( v -> session - .createSelectionQuery( "from Book", Book.class ) - .setOrder( List.of( desc( isbn ), desc( title ) ) ) - .getResultList() - .invoke( isbnDesc -> assertThat( isbnDesc ).containsExactly( book1, book2 ) ) - ) - ) ); - } - - @Test - public void testAscDescWithNamedParam(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( asc( title ) ) - .getResultList() - .thenAccept( list -> assertThat( list ).containsExactly( book1, book2 ) ) - .thenCompose( v -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( desc( title ) ).getResultList() - .thenAccept( isbnDesc -> assertThat( isbnDesc ).containsExactly( book2, book1 ) ) - ) - ) ); - } - - @Test - public void testAscDescWithNamedParamMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( asc( title ) ) - .getResultList() - .invoke( list -> assertThat( list ).containsExactly( book1, book2 ) ) - .chain( v -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( desc( title ) ) - .getResultList() - .invoke( isbnDesc -> assertThat( isbnDesc ).containsExactly( book2, book1 ) ) - ) - ) ); - } - - @Test - public void testAscDescWithPositionalParam(VertxTestContext context) { - test( context, getSessionFactory().withSession( session -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( asc( title ) ) - .getResultList() - .thenAccept( list -> assertThat( list ).containsExactly( book1, book2 ) ) - .thenCompose( v -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( desc( title ) ) - .getResultList() - .thenAccept( isbnDesc -> assertThat( isbnDesc ).containsExactly( book2, book1 ) ) - ) - ) ); - } - - @Test - public void testAscDescWithPositionalParamMutiny(VertxTestContext context) { - test( context, getMutinySessionFactory().withSession( session -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( asc( title ) ) - .getResultList() - .invoke( list -> assertThat( list ).containsExactly( book1, book2 ) ) - .chain( v -> session - .createSelectionQuery( "from Book where title like :title", Book.class ) - .setParameter( "title", "%Hibernate%" ) - .setOrder( desc( title ) ) - .getResultList() - .invoke( isbnDesc -> assertThat( isbnDesc ).containsExactly( book2, book1 ) ) - ) - ) ); - } - - private void assertOrderByBookArray(List resultList, Book... expectedBooks) { - List books = resultList.stream() - .map( objects -> new Book( (String) objects[0], (String) objects[1] ) ) - .collect( toList() ); - assertThat( books ).containsExactly( expectedBooks ); - } - - private SingularAttribute attribute(String name) { - MappingMetamodelImpl metamodel = (MappingMetamodelImpl) getSessionFactory().getMetamodel(); - EntityDomainType bookType = metamodel.getJpaMetamodel().findEntityType( Book.class ); - return bookType.findSingularAttribute( name ); - } - - @Entity(name = "Book") - @Table(name = "OrderTest_Book" ) - static class Book { - @Id - String isbn; - String title; - - Book(String isbn, String title) { - this.isbn = isbn; - this.title = title; - } - - Book() { - } - - @Override - public boolean equals(Object o) { - if ( this == o ) { - return true; - } - if ( o == null || getClass() != o.getClass() ) { - return false; - } - Book book = (Book) o; - return Objects.equals( isbn, book.isbn ) && Objects.equals( - title, - book.title - ); - } - - @Override - public int hashCode() { - return Objects.hash( isbn, title ); - } - - @Override - public String toString() { - return isbn + ":" + title; - } - } -} diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QuerySpecificationTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QuerySpecificationTest.java new file mode 100644 index 000000000..01f85f35e --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QuerySpecificationTest.java @@ -0,0 +1,423 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl; +import org.hibernate.query.Order; +import org.hibernate.query.restriction.Restriction; +import org.hibernate.query.specification.MutationSpecification; +import org.hibernate.query.specification.SelectionSpecification; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +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.TypedQueryReference; +import jakarta.persistence.metamodel.SingularAttribute; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.query.Order.asc; +import static org.hibernate.query.Order.desc; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +/** + * Test for queries created using {@link SelectionSpecification}. + */ +@Timeout(value = 10, timeUnit = MINUTES) +public class QuerySpecificationTest extends BaseReactiveTest { + static final Book hibBook = new Book( 1L, "Hibernate in Action" ); + static final Book jpBook = new Book( 3L, "Java Persistence with Hibernate" ); + static final Book animalFarmBook = new Book( 2L, "Animal Farm" ); + + // This is only added when testing order with multiple columns + static final Book animalFarmBook2 = new Book( 4L, "Animal Farm" ); + + @Override + protected Collection> annotatedEntities() { + return List.of( Book.class ); + } + + @BeforeEach + public void populateDB(VertxTestContext context) { + test( context, getSessionFactory().withTransaction( session -> session + .persist( hibBook, jpBook, animalFarmBook ) ) + ); + } + + static Stream singleColumnOrderExpectation() { + return Stream.of( + arguments( asc( Book.class, "title" ), List.of( animalFarmBook, hibBook, jpBook ) ), + arguments( desc( Book.class, "title" ), List.of( jpBook, hibBook, animalFarmBook ) ), + arguments( asc( Book.class, "isbn" ), List.of( hibBook, animalFarmBook, jpBook ) ), + arguments( desc( Book.class, "isbn" ), List.of( jpBook, animalFarmBook, hibBook ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleColumnOrderWithStage(Order order, List expectedList, VertxTestContext context) { + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( order ) + .reference(); + + test( context, getSessionFactory() + .withSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .thenAccept( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleColumnOrderWithStageStateless(Order order, List expectedList, VertxTestContext context) { + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( order ) + .reference(); + + test( context, getSessionFactory() + .withStatelessSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .thenAccept( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleColumnOrderWithMutiny(Order order, List expectedList, VertxTestContext context) { + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( order ) + .reference(); + + test( context, getMutinySessionFactory() + .withSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .invoke( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleColumnOrderWithMutinyStateless(Order order, List expectedList, VertxTestContext context) { + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( order ) + .reference(); + + test( context, getMutinySessionFactory() + .withStatelessSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .invoke( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleAttributeOrderWithStage(Order order, List expectedList, VertxTestContext context) { + final SingularAttribute attribute = attribute( order.attributeName() ); + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( Order.by( attribute, order.direction() ) ) + .reference(); + + test( context, getSessionFactory() + .withSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .thenAccept( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleAttributeOrderWithStageStateless(Order order, List expectedList, VertxTestContext context) { + final SingularAttribute attribute = attribute( order.attributeName() ); + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( Order.by( attribute, order.direction() ) ) + .reference(); + + test( context, getSessionFactory() + .withStatelessSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .thenAccept( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleAttributeOrderWithMutiny(Order order, List expectedList, VertxTestContext context) { + final SingularAttribute attribute = attribute( order.attributeName() ); + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( Order.by( attribute, order.direction() ) ) + .reference(); + + test( context, getMutinySessionFactory() + .withSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .invoke( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("singleColumnOrderExpectation") + public void singleAttributeOrderWithMutinyStateless(Order order, List expectedList, VertxTestContext context) { + final SingularAttribute attribute = attribute( order.attributeName() ); + var bookReference = SelectionSpecification + .create( Book.class, "from Book" ) + .sort( Order.by( attribute, order.direction() ) ) + .reference(); + + test( context, getMutinySessionFactory() + .withStatelessSession( session -> session + .createQuery( bookReference ) + .getResultList() ) + .invoke( books -> assertThat( books ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("multipleColumnOrderExpectation") + public void multipleColumnsOrderWithStage(List> orders, List expectedList, VertxTestContext context) { + var columnsSpec = SelectionSpecification + .create( Book.class, "from Book" ); + for ( Order order : orders ) { + columnsSpec.sort( order ); + } + + test( context, getSessionFactory() + .withTransaction( session -> session.persist( animalFarmBook2 ) ) + .thenCompose( v -> getSessionFactory().withSession( session -> session + .createQuery( columnsSpec.reference() ) + .getResultList() ) ) + .thenAccept( list -> assertThat( list ).isEqualTo( expectedList ) ) + ); + } + + static Stream multipleColumnOrderExpectation() { + return Stream.of( + arguments( + List.of( asc( Book.class, "title" ), asc( Book.class, "isbn" ) ), + List.of( animalFarmBook, animalFarmBook2, hibBook, jpBook ) + ), + arguments( + List.of( asc( Book.class, "title" ), desc( Book.class, "isbn" ) ), + List.of( animalFarmBook2, animalFarmBook, hibBook, jpBook ) + ), + arguments( + List.of( desc( Book.class, "isbn" ), asc( Book.class, "title" ) ), + List.of( animalFarmBook2, jpBook, animalFarmBook, hibBook ) + ), + arguments( + List.of( desc( Book.class, "isbn" ), desc( Book.class, "title" ) ), + List.of( animalFarmBook2, jpBook, animalFarmBook, hibBook ) + ) + ); + } + + @ParameterizedTest + @MethodSource("multipleColumnOrderExpectation") + public void multipleColumnsOrderWithStageStateless(List> orders, List expectedList, VertxTestContext context) { + var columnsSpec = SelectionSpecification + .create( Book.class, "from Book" ); + for ( Order order : orders ) { + columnsSpec.sort( order ); + } + + test( context, getSessionFactory() + .withTransaction( session -> session.persist( animalFarmBook2 ) ) + .thenCompose( v -> getSessionFactory().withStatelessSession( session -> session + .createQuery( columnsSpec.reference() ) + .getResultList() ) ) + .thenAccept( list -> assertThat( list ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("multipleColumnOrderExpectation") + public void multipleColumnsOrderWithMutiny(List> orders, List expectedList, VertxTestContext context) { + var columnsSpec = SelectionSpecification + .create( Book.class, "from Book" ); + for ( Order order : orders ) { + columnsSpec.sort( order ); + } + + test( context, getMutinySessionFactory() + .withTransaction( session -> session.persist( animalFarmBook2 ) ) + .chain( v -> getMutinySessionFactory().withSession( session -> session + .createQuery( columnsSpec.reference() ) + .getResultList() ) ) + .invoke( list -> assertThat( list ).isEqualTo( expectedList ) ) + ); + } + + @ParameterizedTest + @MethodSource("multipleColumnOrderExpectation") + public void multipleColumnsOrderWithMutinyStateless(List> orders, List expectedList, VertxTestContext context) { + var columnsSpec = SelectionSpecification + .create( Book.class, "from Book" ); + for ( Order order : orders ) { + columnsSpec.sort( order ); + } + + test( context, getMutinySessionFactory() + .withTransaction( session -> session.persist( animalFarmBook2 ) ) + .chain( v -> getMutinySessionFactory().withStatelessSession( session -> session + .createQuery( columnsSpec.reference() ) + .getResultList() ) ) + .invoke( list -> assertThat( list ).isEqualTo( expectedList ) ) + ); + } + + @Test + public void mutationSpecificationWithStage(VertxTestContext context) { + SingularAttribute title = (SingularAttribute) attribute( "title" ); + TypedQueryReference deleteAnimalFarm = MutationSpecification + .create( Book.class, "delete Book" ) + .restrict( Restriction.equalIgnoringCase( title, animalFarmBook.title ) ) + .reference(); + + test( context, getSessionFactory() + .withTransaction( session -> session.persist( animalFarmBook2 ) ) + .thenCompose( v -> getSessionFactory().withTransaction( session -> session + .createQuery( deleteAnimalFarm ) + .executeUpdate() ) ) + .thenAccept( deleted -> assertThat( deleted ).isEqualTo( 2 ) ) + .thenCompose( v -> getSessionFactory().withSession( session -> session + .createQuery( "from Book", Book.class ).getResultList() ) ) + .thenAccept( list -> assertThat( list ).containsExactlyInAnyOrder( hibBook, jpBook ) ) + ); + } + + @Test + public void mutationSpecificationWithStageStateless(VertxTestContext context) { + SingularAttribute title = (SingularAttribute) attribute( "title" ); + TypedQueryReference deleteAnimalFarm = MutationSpecification + .create( Book.class, "delete Book" ) + .restrict( Restriction.equalIgnoringCase( title, animalFarmBook.title ) ) + .reference(); + + test( context, getSessionFactory() + .withTransaction( session -> session.persist( animalFarmBook2 ) ) + .thenCompose( v -> getSessionFactory().withStatelessTransaction( session -> session + .createQuery( deleteAnimalFarm ) + .executeUpdate() ) ) + .thenAccept( deleted -> assertThat( deleted ).isEqualTo( 2 ) ) + .thenCompose( v -> getSessionFactory().withSession( session -> session + .createQuery( "from Book", Book.class ).getResultList() ) ) + .thenAccept( list -> assertThat( list ).containsExactlyInAnyOrder( hibBook, jpBook ) ) + ); + } + + @Test + public void mutationSpecificationWithMutiny(VertxTestContext context) { + SingularAttribute title = (SingularAttribute) attribute( "title" ); + TypedQueryReference deleteAnimalFarm = MutationSpecification + .create( Book.class, "delete Book" ) + .restrict( Restriction.equalIgnoringCase( title, animalFarmBook.title ) ) + .reference(); + + test( context, getMutinySessionFactory() + .withTransaction( session -> session.persist( animalFarmBook2 ) ) + .chain( v -> getMutinySessionFactory().withTransaction( session -> session + .createQuery( deleteAnimalFarm ) + .executeUpdate() ) ) + .invoke( deleted -> assertThat( deleted ).isEqualTo( 2 ) ) + .chain( () -> getMutinySessionFactory().withSession( session -> session + .createQuery( "from Book", Book.class ).getResultList() ) ) + .invoke( list -> assertThat( list ).containsExactlyInAnyOrder( hibBook, jpBook ) ) + ); + } + + @Test + public void mutationSpecificationWithMutinyStateless(VertxTestContext context) { + SingularAttribute title = (SingularAttribute) attribute( "title" ); + TypedQueryReference deleteAnimalFarm = MutationSpecification + .create( Book.class, "delete Book" ) + .restrict( Restriction.equalIgnoringCase( title, animalFarmBook.title ) ) + .reference(); + + test( context, getMutinySessionFactory() + .withStatelessTransaction( session -> session.insert( animalFarmBook2 ) ) + .chain( v -> getMutinySessionFactory().withStatelessTransaction( session -> session + .createQuery( deleteAnimalFarm ) + .executeUpdate() ) ) + .invoke( deleted -> assertThat( deleted ).isEqualTo( 2 ) ) + .chain( () -> getMutinySessionFactory().withStatelessSession( session -> session + .createQuery( "from Book", Book.class ).getResultList() ) ) + .invoke( list -> assertThat( list ).containsExactlyInAnyOrder( hibBook, jpBook ) ) + ); + } + + private SingularAttribute attribute(String name) { + MappingMetamodelImpl metamodel = (MappingMetamodelImpl) getSessionFactory().getMetamodel(); + EntityDomainType bookType = metamodel.getJpaMetamodel().findEntityType( Book.class ); + return bookType.findSingularAttribute( name ); + } + + @Entity(name = "Book") + @Table(name = "OrderTest_Book" ) + public static class Book { + @Id + Long isbn; + String title; + + Book(Long isbn, String title) { + this.isbn = isbn; + this.title = title; + } + + Book() { + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Book book = (Book) o; + return Objects.equals( isbn, book.isbn ) && Objects.equals( + title, + book.title + ); + } + + @Override + public int hashCode() { + return Objects.hash( isbn, title ); + } + + @Override + public String toString() { + return isbn + ":" + title; + } + } +} diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java index a636bc5a9..d57f9103a 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java @@ -57,10 +57,10 @@ class OracleDatabase implements TestableDatabase { expectedDBTypeForClass.put( Integer.class, "NUMBER" ); expectedDBTypeForClass.put( long.class, "NUMBER" ); expectedDBTypeForClass.put( Long.class, "NUMBER" ); - expectedDBTypeForClass.put( float.class, "FLOAT" ); - expectedDBTypeForClass.put( Float.class, "FLOAT" ); - expectedDBTypeForClass.put( double.class, "FLOAT" ); - expectedDBTypeForClass.put( Double.class, "FLOAT" ); + expectedDBTypeForClass.put( float.class, "BINARY_FLOAT" ); + expectedDBTypeForClass.put( Float.class, "BINARY_FLOAT" ); + expectedDBTypeForClass.put( double.class, "BINARY_DOUBLE" ); + expectedDBTypeForClass.put( Double.class, "BINARY_DOUBLE" ); expectedDBTypeForClass.put( byte.class, "NUMBER" ); expectedDBTypeForClass.put( Byte.class, "NUMBER" ); expectedDBTypeForClass.put( URL.class, "VARCHAR2" );