HHH-15078 - Support for Tuple and SelectionQuery
This commit is contained in:
parent
88938ac482
commit
aa0c57aa5c
|
@ -86,6 +86,10 @@ import static org.hibernate.jpa.QueryHints.HINT_READONLY;
|
||||||
public abstract class AbstractSelectionQuery<R>
|
public abstract class AbstractSelectionQuery<R>
|
||||||
extends AbstractCommonQueryContract
|
extends AbstractCommonQueryContract
|
||||||
implements SelectionQuery<R>, DomainQueryExecutionContext {
|
implements SelectionQuery<R>, DomainQueryExecutionContext {
|
||||||
|
/**
|
||||||
|
* The value used for {@link #getQueryString} for Criteria-based queries
|
||||||
|
*/
|
||||||
|
public static final String CRITERIA_HQL_STRING = "<criteria>";
|
||||||
|
|
||||||
private Callback callback;
|
private Callback callback;
|
||||||
|
|
||||||
|
@ -189,10 +193,17 @@ public abstract class AbstractSelectionQuery<R>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract String getQueryString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used during handling of Criteria queries
|
||||||
|
*/
|
||||||
protected void visitQueryReturnType(
|
protected void visitQueryReturnType(
|
||||||
SqmQueryPart<R> queryPart,
|
SqmQueryPart<R> queryPart,
|
||||||
Class<R> resultType,
|
Class<R> resultType,
|
||||||
SessionFactoryImplementor factory) {
|
SessionFactoryImplementor factory) {
|
||||||
|
assert getQueryString().equals( CRITERIA_HQL_STRING );
|
||||||
|
|
||||||
if ( queryPart instanceof SqmQuerySpec<?> ) {
|
if ( queryPart instanceof SqmQuerySpec<?> ) {
|
||||||
final SqmQuerySpec<R> sqmQuerySpec = (SqmQuerySpec<R>) queryPart;
|
final SqmQuerySpec<R> sqmQuerySpec = (SqmQuerySpec<R>) queryPart;
|
||||||
final List<SqmSelection<?>> sqmSelections = sqmQuerySpec.getSelectClause().getSelections();
|
final List<SqmSelection<?>> sqmSelections = sqmQuerySpec.getSelectClause().getSelections();
|
||||||
|
|
|
@ -119,11 +119,6 @@ import static org.hibernate.query.sqm.internal.SqmUtil.isSelect;
|
||||||
public class QuerySqmImpl<R>
|
public class QuerySqmImpl<R>
|
||||||
extends AbstractSelectionQuery<R>
|
extends AbstractSelectionQuery<R>
|
||||||
implements SqmQueryImplementor<R>, InterpretationsKeySource, DomainQueryExecutionContext {
|
implements SqmQueryImplementor<R>, InterpretationsKeySource, DomainQueryExecutionContext {
|
||||||
|
|
||||||
/**
|
|
||||||
* The value used for {@link #getQueryString} for Criteria-based queries
|
|
||||||
*/
|
|
||||||
public static final String CRITERIA_HQL_STRING = "<criteria>";
|
|
||||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QuerySqmImpl.class );
|
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QuerySqmImpl.class );
|
||||||
|
|
||||||
private final String hql;
|
private final String hql;
|
||||||
|
|
|
@ -18,6 +18,7 @@ import jakarta.persistence.FlushModeType;
|
||||||
import jakarta.persistence.LockModeType;
|
import jakarta.persistence.LockModeType;
|
||||||
import jakarta.persistence.Parameter;
|
import jakarta.persistence.Parameter;
|
||||||
import jakarta.persistence.TemporalType;
|
import jakarta.persistence.TemporalType;
|
||||||
|
import jakarta.persistence.Tuple;
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
|
@ -78,8 +79,6 @@ import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOption
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implements SqmSelectionQuery<R>, InterpretationsKeySource {
|
public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implements SqmSelectionQuery<R>, InterpretationsKeySource {
|
||||||
public static final String CRITERIA_HQL_STRING = "<criteria>";
|
|
||||||
|
|
||||||
private final String hql;
|
private final String hql;
|
||||||
private final SqmSelectStatement<R> sqm;
|
private final SqmSelectStatement<R> sqm;
|
||||||
|
|
||||||
|
@ -105,14 +104,19 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
||||||
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
|
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
|
||||||
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
|
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
|
||||||
|
|
||||||
visitQueryReturnType( sqm.getQueryPart(), expectedResultType, getSessionFactory() );
|
// visitQueryReturnType( sqm.getQueryPart(), expectedResultType, getSessionFactory() );
|
||||||
this.resultType = determineResultType( sqm, expectedResultType );
|
this.resultType = determineResultType( sqm, expectedResultType );
|
||||||
|
|
||||||
setComment( hql );
|
setComment( hql );
|
||||||
this.tupleMetadata = null;
|
this.tupleMetadata = buildTupleMetadata( sqm, expectedResultType );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> Class<T> determineResultType(SqmSelectStatement<?> sqm, Class<?> expectedResultType) {
|
private static <T> Class<T> determineResultType(SqmSelectStatement<?> sqm, Class<?> expectedResultType) {
|
||||||
|
if ( expectedResultType != null && expectedResultType.equals( Tuple.class ) ) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return (Class<T>) Tuple.class;
|
||||||
|
}
|
||||||
|
|
||||||
if ( expectedResultType == null || ! expectedResultType.isArray() ) {
|
if ( expectedResultType == null || ! expectedResultType.isArray() ) {
|
||||||
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
|
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
|
||||||
if ( selections.size() == 1 ) {
|
if ( selections.size() == 1 ) {
|
||||||
|
@ -152,10 +156,9 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
||||||
|
|
||||||
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
|
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
|
||||||
|
|
||||||
visitQueryReturnType( sqm.getQueryPart(), resultType, getSessionFactory() );
|
|
||||||
setComment( hql );
|
setComment( hql );
|
||||||
|
|
||||||
applyOptions( memento );
|
applyOptions( memento );
|
||||||
|
|
||||||
this.tupleMetadata = buildTupleMetadata( sqm, resultType );
|
this.tupleMetadata = buildTupleMetadata( sqm, resultType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,13 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.query.sqm;
|
package org.hibernate.orm.test.query.sqm;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import jakarta.persistence.Basic;
|
import jakarta.persistence.Basic;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.NamedQuery;
|
import jakarta.persistence.NamedQuery;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Tuple;
|
||||||
|
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
@ -22,8 +24,10 @@ import org.hibernate.testing.orm.domain.contacts.Contact;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,6 +67,54 @@ public class BasicSelectionQueryTests {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createDummyEntity(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.persist( new DummyEntity( 1, "whatever" ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String tuple_selection_hql = "select c.id as id, c.name as name from DummyEntity c";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tupleSelectionTestBaseline(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
checkResults( session.createQuery( tuple_selection_hql, Tuple.class ), session );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tupleSelectionTest(SessionFactoryScope scope) {
|
||||||
|
createDummyEntity( scope );
|
||||||
|
|
||||||
|
// first make sure we get back the correct results via list
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final SelectionQuery<Tuple> selectionQuery = session.createSelectionQuery( tuple_selection_hql, Tuple.class );
|
||||||
|
|
||||||
|
final List<Tuple> tuples = selectionQuery.list();
|
||||||
|
assertThat( tuples ).hasSize( 1 );
|
||||||
|
|
||||||
|
assertThat( tuples.get( 0 ) ).isInstanceOf( Tuple.class );
|
||||||
|
final Tuple tuple = tuples.get( 0 );
|
||||||
|
assertThat( tuple.get( 0 ) ).isEqualTo( 1 );
|
||||||
|
assertThat( tuple.get( "id" ) ).isEqualTo( 1 );
|
||||||
|
assertThat( tuple.get( 1 ) ).isEqualTo( "whatever" );
|
||||||
|
assertThat( tuple.get( "name" ) ).isEqualTo( "whatever" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// next make sure the rest of the execution methods work
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final SelectionQuery<Tuple> selectionQuery = session.createSelectionQuery( tuple_selection_hql, Tuple.class );
|
||||||
|
checkResults( selectionQuery, session );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void dropTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete DummyEntity" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void rawScalarSelectTest(SessionFactoryScope scope) {
|
public void rawScalarSelectTest(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( (session) -> {
|
scope.inTransaction( (session) -> {
|
||||||
|
|
Loading…
Reference in New Issue