HHH-11573 Query based on type expressions
This commit is contained in:
parent
9d75e6d620
commit
1eec41a136
|
@ -482,6 +482,11 @@ public class Parameters {
|
||||||
expressions.add( expression.toString() );
|
expressions.add( expression.toString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addEntityTypeRestriction(String alias, String entityName) {
|
||||||
|
String expression = String.format( "type(%s) = %s", alias, entityName );
|
||||||
|
expressions.add( expression );
|
||||||
|
}
|
||||||
|
|
||||||
private void append(StringBuilder sb, String toAppend, MutableBoolean isFirst) {
|
private void append(StringBuilder sb, String toAppend, MutableBoolean isFirst) {
|
||||||
if ( !isFirst.isSet() ) {
|
if ( !isFirst.isSet() ) {
|
||||||
sb.append( " " ).append( connective ).append( " " );
|
sb.append( " " ).append( connective ).append( " " );
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
|
import org.hibernate.envers.internal.tools.EntityTools;
|
||||||
import org.hibernate.envers.query.criteria.AuditConjunction;
|
import org.hibernate.envers.query.criteria.AuditConjunction;
|
||||||
import org.hibernate.envers.query.criteria.AuditCriterion;
|
import org.hibernate.envers.query.criteria.AuditCriterion;
|
||||||
import org.hibernate.envers.query.criteria.AuditDisjunction;
|
import org.hibernate.envers.query.criteria.AuditDisjunction;
|
||||||
|
@ -18,6 +19,7 @@ import org.hibernate.envers.query.criteria.AuditFunction;
|
||||||
import org.hibernate.envers.query.criteria.AuditId;
|
import org.hibernate.envers.query.criteria.AuditId;
|
||||||
import org.hibernate.envers.query.criteria.AuditProperty;
|
import org.hibernate.envers.query.criteria.AuditProperty;
|
||||||
import org.hibernate.envers.query.criteria.AuditRelatedId;
|
import org.hibernate.envers.query.criteria.AuditRelatedId;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.EntityTypeAuditExpression;
|
||||||
import org.hibernate.envers.query.criteria.internal.LogicalAuditExpression;
|
import org.hibernate.envers.query.criteria.internal.LogicalAuditExpression;
|
||||||
import org.hibernate.envers.query.criteria.internal.NotAuditExpression;
|
import org.hibernate.envers.query.criteria.internal.NotAuditExpression;
|
||||||
import org.hibernate.envers.query.internal.property.EntityPropertyName;
|
import org.hibernate.envers.query.internal.property.EntityPropertyName;
|
||||||
|
@ -192,7 +194,7 @@ public class AuditEntity {
|
||||||
* <li>AuditEntity.function("concat", AuditEntity.function("upper", AuditEntity.property("prop1")),
|
* <li>AuditEntity.function("concat", AuditEntity.function("upper", AuditEntity.property("prop1")),
|
||||||
* AuditEntity.function("substring", AuditEntity.property("prop2"), 1, 2))</li>
|
* AuditEntity.function("substring", AuditEntity.property("prop2"), 1, 2))</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param function the name of the function
|
* @param function the name of the function
|
||||||
* @param arguments the arguments of the function. A function argument can either be
|
* @param arguments the arguments of the function. A function argument can either be
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -207,4 +209,44 @@ public class AuditEntity {
|
||||||
Collections.addAll( argumentList, arguments );
|
Collections.addAll( argumentList, arguments );
|
||||||
return new AuditFunction( function, argumentList );
|
return new AuditFunction( function, argumentList );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a restriction for the type of the current entity.
|
||||||
|
*
|
||||||
|
* @param the entity type to restrict the current alias to
|
||||||
|
*/
|
||||||
|
public static AuditCriterion entityType(final Class<?> type) {
|
||||||
|
return entityType( null, type );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a restriction for the type of the current entity.
|
||||||
|
*
|
||||||
|
* @param entityName the entity name to restrict the current alias to
|
||||||
|
*/
|
||||||
|
public static AuditCriterion entityType(final String entityName) {
|
||||||
|
return entityType( null, entityName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a restriction for the type of the entity of the specified alias.
|
||||||
|
*
|
||||||
|
* @param alias the alias to restrict. If null is specified, the current alias is used
|
||||||
|
* @param type the entity type to restrict the alias to
|
||||||
|
*/
|
||||||
|
public static AuditCriterion entityType(final String alias, final Class<?> type) {
|
||||||
|
Class<?> unproxiedType = EntityTools.getTargetClassIfProxied( type );
|
||||||
|
return entityType( alias, unproxiedType.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a restriction for the type of the entity of the specified alias.
|
||||||
|
*
|
||||||
|
* @param alias the alias to restrict. If null is specified, the current alias is used
|
||||||
|
* @param entityName the entity name to restrict the alias to
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static AuditCriterion entityType(final String alias, final String entityName) {
|
||||||
|
return new EntityTypeAuditExpression( alias, entityName );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.envers.query.criteria.internal;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.query.criteria.AuditCriterion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class EntityTypeAuditExpression implements AuditCriterion {
|
||||||
|
|
||||||
|
private String alias;
|
||||||
|
private String entityName;
|
||||||
|
|
||||||
|
public EntityTypeAuditExpression(
|
||||||
|
String alias,
|
||||||
|
String entityName) {
|
||||||
|
this.alias = alias;
|
||||||
|
this.entityName = entityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToQuery(
|
||||||
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder qb,
|
||||||
|
Parameters parameters) {
|
||||||
|
String effectiveAlias = alias == null ? baseAlias : alias;
|
||||||
|
String effectiveEntityName = entityName;
|
||||||
|
if ( enversService.getEntitiesConfigurations().isVersioned( effectiveEntityName ) ) {
|
||||||
|
effectiveEntityName = enversService.getConfig().getAuditEntityName( effectiveEntityName );
|
||||||
|
}
|
||||||
|
parameters.addEntityTypeRestriction( effectiveAlias, effectiveEntityName );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.envers.test.integration.query;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Inheritance;
|
||||||
|
import jakarta.persistence.InheritanceType;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
import org.hibernate.envers.query.AuditEntity;
|
||||||
|
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
|
||||||
|
import org.hibernate.orm.test.envers.Priority;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class EntityTypeQueryTest extends BaseEnversJPAFunctionalTestCase {
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Audited
|
||||||
|
@Inheritance(strategy = InheritanceType.JOINED)
|
||||||
|
public static class EntityA {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Audited
|
||||||
|
public static class EntityB extends EntityA {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityA a1;
|
||||||
|
private EntityA a2;
|
||||||
|
private EntityB b1;
|
||||||
|
private EntityB b2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[]{ EntityA.class, EntityB.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Priority(10)
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
a1 = new EntityA();
|
||||||
|
a1.setName( "a1" );
|
||||||
|
em.persist( a1 );
|
||||||
|
a2 = new EntityA();
|
||||||
|
a2.setName( "a2" );
|
||||||
|
em.persist( a2 );
|
||||||
|
b1 = new EntityB();
|
||||||
|
b1.setName( "b1" );
|
||||||
|
em.persist( b1 );
|
||||||
|
b2 = new EntityB();
|
||||||
|
b2.setName( "b2" );
|
||||||
|
em.persist( b2 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRestrictToSubType() {
|
||||||
|
List<?> list = getAuditReader().createQuery().forEntitiesAtRevision( EntityA.class, 1 )
|
||||||
|
.add( AuditEntity.entityType( EntityB.class ) ).addProjection( AuditEntity.property( "name" ) ).getResultList();
|
||||||
|
assertEquals( "Expected only entities of type EntityB to be selected", list( "b1", "b2" ), list );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRestrictToSuperType() {
|
||||||
|
List<?> list = getAuditReader().createQuery().forEntitiesAtRevision( EntityA.class, 1 )
|
||||||
|
.add( AuditEntity.entityType( EntityA.class ) ).addProjection( AuditEntity.property( "name" ) ).getResultList();
|
||||||
|
assertEquals( "Expected only entities of type EntityA to be selected", list( "a1", "a2" ), list );
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> list(final String... elements) {
|
||||||
|
final List<String> result = new ArrayList<>();
|
||||||
|
Collections.addAll( result, elements );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue