HHH-11452 Added possibility to apply the like operator on a function criterion. Added possibility to use the id of an entity as function argument.
This commit is contained in:
parent
640bd85975
commit
e50037ec8c
|
@ -317,14 +317,28 @@ public class Parameters {
|
|||
* Add where clause with a function call on the left and a scalar value on the right.
|
||||
*
|
||||
* @param configuration the configuration.
|
||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||
* @param function the function.
|
||||
* @param op the operator.
|
||||
* @param value the scalar value.
|
||||
*/
|
||||
public void addWhereWithFunction(Configuration configuration, AuditFunction function, String op, Object value) {
|
||||
public void addWhereWithFunction(
|
||||
Configuration configuration,
|
||||
Map<String, String> aliasToEntityNameMap,
|
||||
AuditFunction function,
|
||||
String op,
|
||||
Object value) {
|
||||
final StringBuilder expression = new StringBuilder();
|
||||
|
||||
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, function );
|
||||
QueryBuilder.appendFunctionArgument(
|
||||
configuration,
|
||||
aliasToEntityNameMap,
|
||||
queryParamCounter,
|
||||
localQueryParamValues,
|
||||
alias,
|
||||
expression,
|
||||
function
|
||||
);
|
||||
|
||||
expression.append( ' ' ).append( op );
|
||||
|
||||
|
@ -339,15 +353,30 @@ public class Parameters {
|
|||
* Add a where clause with a function call on the left and an optionally aliased property on the right.
|
||||
*
|
||||
* @param configuration the configuration.
|
||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||
* @param function the function.
|
||||
* @param op the operator.
|
||||
* @param aliasRight the optional alias of the right property, may be {@literal null}
|
||||
* @param right the property.
|
||||
*/
|
||||
public void addWhereWithFunction(Configuration configuration, AuditFunction function, String op, String aliasRight, String right) {
|
||||
public void addWhereWithFunction(
|
||||
Configuration configuration,
|
||||
Map<String, String> aliasToEntityNameMap,
|
||||
AuditFunction function,
|
||||
String op,
|
||||
String aliasRight,
|
||||
String right) {
|
||||
final StringBuilder expression = new StringBuilder();
|
||||
|
||||
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, function );
|
||||
QueryBuilder.appendFunctionArgument(
|
||||
configuration,
|
||||
aliasToEntityNameMap,
|
||||
queryParamCounter,
|
||||
localQueryParamValues,
|
||||
alias,
|
||||
expression,
|
||||
function
|
||||
);
|
||||
|
||||
expression.append( ' ' ).append( op ).append( ' ' );
|
||||
|
||||
|
@ -363,12 +392,19 @@ public class Parameters {
|
|||
* Adds a where clause with a left (optionally aliased) property and a function call on the right side.
|
||||
*
|
||||
* @param configuration the configuration.
|
||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||
* @param aliasLeft the optional alias of the left property, may be {@literal null}
|
||||
* @param left the property.
|
||||
* @param op the operator.
|
||||
* @param function the function.
|
||||
*/
|
||||
public void addWhereWithFunction(Configuration configuration, String aliasLeft, String left, String op, AuditFunction function) {
|
||||
public void addWhereWithFunction(
|
||||
Configuration configuration,
|
||||
Map<String, String> aliasToEntityNameMap,
|
||||
String aliasLeft,
|
||||
String left,
|
||||
String op,
|
||||
AuditFunction function) {
|
||||
final StringBuilder expression = new StringBuilder();
|
||||
|
||||
if ( aliasLeft != null ) {
|
||||
|
@ -378,7 +414,15 @@ public class Parameters {
|
|||
|
||||
expression.append( ' ' ).append( op ).append( ' ' );
|
||||
|
||||
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, function );
|
||||
QueryBuilder.appendFunctionArgument(
|
||||
configuration,
|
||||
aliasToEntityNameMap,
|
||||
queryParamCounter,
|
||||
localQueryParamValues,
|
||||
alias,
|
||||
expression,
|
||||
function
|
||||
);
|
||||
|
||||
expressions.add( expression.toString() );
|
||||
}
|
||||
|
@ -387,18 +431,40 @@ public class Parameters {
|
|||
* Adds a where clause with a function call on both the left and right of the predicate.
|
||||
*
|
||||
* @param configuration the configuration.
|
||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||
* @param left the left-side function.
|
||||
* @param op the operator.
|
||||
* @param right the right-side function.
|
||||
*/
|
||||
public void addWhereWithFunction(Configuration configuration, AuditFunction left, String op, AuditFunction right) {
|
||||
public void addWhereWithFunction(
|
||||
Configuration configuration,
|
||||
Map<String, String> aliasToEntityNameMap,
|
||||
AuditFunction left,
|
||||
String op,
|
||||
AuditFunction right) {
|
||||
final StringBuilder expression = new StringBuilder();
|
||||
|
||||
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, left );
|
||||
QueryBuilder.appendFunctionArgument(
|
||||
configuration,
|
||||
aliasToEntityNameMap,
|
||||
queryParamCounter,
|
||||
localQueryParamValues,
|
||||
alias,
|
||||
expression,
|
||||
left
|
||||
);
|
||||
|
||||
expression.append( ' ' ).append( op ).append( ' ' );
|
||||
|
||||
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, right );
|
||||
QueryBuilder.appendFunctionArgument(
|
||||
configuration,
|
||||
aliasToEntityNameMap,
|
||||
queryParamCounter,
|
||||
localQueryParamValues,
|
||||
alias,
|
||||
expression,
|
||||
right
|
||||
);
|
||||
|
||||
expressions.add( expression.toString() );
|
||||
}
|
||||
|
|
|
@ -12,18 +12,23 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.boot.internal.EnversService;
|
||||
import org.hibernate.envers.configuration.Configuration;
|
||||
import org.hibernate.envers.function.OrderByFragmentFunction;
|
||||
import org.hibernate.envers.internal.entities.RevisionTypeType;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.QueryParameterData;
|
||||
import org.hibernate.envers.internal.tools.MutableInteger;
|
||||
import org.hibernate.envers.internal.tools.StringTools;
|
||||
import org.hibernate.envers.internal.tools.Triple;
|
||||
import org.hibernate.envers.query.criteria.AuditFunction;
|
||||
import org.hibernate.envers.query.criteria.AuditId;
|
||||
import org.hibernate.envers.query.criteria.AuditProperty;
|
||||
import org.hibernate.envers.tools.Pair;
|
||||
import org.hibernate.query.Query;
|
||||
|
@ -214,14 +219,23 @@ public class QueryBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
public void addProjection(Configuration configuration, AuditFunction function) {
|
||||
public void addProjection(Configuration configuration, Map<String, String> aliasToEntityNameMap, AuditFunction function) {
|
||||
final StringBuilder expression = new StringBuilder();
|
||||
appendFunctionArgument( configuration, paramCounter, projectionQueryParamValues, alias, expression, function );
|
||||
appendFunctionArgument(
|
||||
configuration,
|
||||
aliasToEntityNameMap,
|
||||
paramCounter,
|
||||
projectionQueryParamValues,
|
||||
alias,
|
||||
expression,
|
||||
function
|
||||
);
|
||||
projections.add( expression.toString() );
|
||||
}
|
||||
|
||||
protected static void appendFunctionArgument(
|
||||
Configuration configuration,
|
||||
Map<String, String> aliasToEntityNameMap,
|
||||
MutableInteger paramCounter,
|
||||
Map<String, Object> queryParamValues,
|
||||
String alias,
|
||||
|
@ -235,11 +249,42 @@ public class QueryBuilder {
|
|||
if ( !first ) {
|
||||
expression.append( ',' );
|
||||
}
|
||||
appendFunctionArgument( configuration, paramCounter, queryParamValues, alias, expression, innerArg );
|
||||
appendFunctionArgument(
|
||||
configuration,
|
||||
aliasToEntityNameMap,
|
||||
paramCounter,
|
||||
queryParamValues,
|
||||
alias,
|
||||
expression,
|
||||
innerArg
|
||||
);
|
||||
first = false;
|
||||
}
|
||||
expression.append( ')' );
|
||||
}
|
||||
else if ( argument instanceof AuditId ) {
|
||||
AuditId<?> id = (AuditId<?>) argument;
|
||||
String prefix = configuration.getOriginalIdPropertyName();
|
||||
String idAlias = id.getAlias( alias );
|
||||
String entityName = aliasToEntityNameMap.get( idAlias );
|
||||
/*
|
||||
* Resolve the name of the id property by reusing the IdMapper.mapToQueryParametersFromId() method. Null is
|
||||
* passed as value because only the name of the property is of interest. TODO: is there a better way to
|
||||
* obtain the name of the id property?
|
||||
*/
|
||||
EnversService enversService = configuration.getEnversService();
|
||||
List<QueryParameterData> parameters = enversService.getEntitiesConfigurations().get( entityName )
|
||||
.getIdMapper()
|
||||
.mapToQueryParametersFromId( null );
|
||||
if ( parameters.size() != 1 ) {
|
||||
throw new HibernateException( "Cannot add id property as function argument when id property is not a single column property" );
|
||||
}
|
||||
String propertyName = parameters.get( 0 ).getProperty( prefix );
|
||||
if ( idAlias != null ) {
|
||||
expression.append( idAlias ).append( '.' );
|
||||
}
|
||||
expression.append( propertyName );
|
||||
}
|
||||
else if ( argument instanceof AuditProperty ) {
|
||||
AuditProperty<?> property = (AuditProperty<?>) argument;
|
||||
String propertyAlias = property.getAlias( alias );
|
||||
|
|
|
@ -55,6 +55,20 @@ public class AuditFunction implements AuditProjection {
|
|||
return new SimpleFunctionAuditExpression( this, value, "<>" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a "like" constraint
|
||||
*/
|
||||
public AuditCriterion like(Object value) {
|
||||
return new SimpleFunctionAuditExpression( this, value, " like " );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a "like" constraint
|
||||
*/
|
||||
public AuditCriterion like(String value, MatchMode matchMode) {
|
||||
return new SimpleFunctionAuditExpression( this, matchMode.toMatchString( value ), " like " );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a "greater than" constraint
|
||||
*/
|
||||
|
@ -222,9 +236,13 @@ public class AuditFunction implements AuditProjection {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addProjectionToQuery(EnversService enversService, AuditReaderImplementor auditReader,
|
||||
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder queryBuilder) {
|
||||
queryBuilder.addProjection( enversService.getConfig(), this );
|
||||
public void addProjectionToQuery(
|
||||
EnversService enversService,
|
||||
AuditReaderImplementor auditReader,
|
||||
Map<String, String> aliasToEntityNameMap,
|
||||
String baseAlias,
|
||||
QueryBuilder queryBuilder) {
|
||||
queryBuilder.addProjection( enversService.getConfig(), aliasToEntityNameMap, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -43,6 +43,12 @@ public class FunctionFunctionAuditExpression implements AuditCriterion {
|
|||
String baseAlias,
|
||||
QueryBuilder queryBuilder,
|
||||
Parameters parameters) {
|
||||
parameters.addWhereWithFunction( enversService.getConfig(), leftFunction, op, rightFunction );
|
||||
parameters.addWhereWithFunction(
|
||||
enversService.getConfig(),
|
||||
aliasToEntityNameMap,
|
||||
leftFunction,
|
||||
op,
|
||||
rightFunction
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,13 @@ public class FunctionPropertyAuditExpression implements AuditCriterion {
|
|||
entityName,
|
||||
propertyNameGetter );
|
||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
||||
parameters.addWhereWithFunction( enversService.getConfig(), effectiveAlias, propertyName, op, function );
|
||||
parameters.addWhereWithFunction(
|
||||
enversService.getConfig(),
|
||||
aliasToEntityNameMap,
|
||||
effectiveAlias,
|
||||
propertyName,
|
||||
op,
|
||||
function
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,13 @@ public class PropertyFunctionAuditExpression implements AuditCriterion {
|
|||
if ( enversService.getEntitiesConfigurations().isVersioned( otherEntityName ) ) {
|
||||
CriteriaTools.checkPropertyNotARelation( enversService, otherEntityName, otherPropertyName );
|
||||
}
|
||||
parameters.addWhereWithFunction( enversService.getConfig(), function, op, effectiveOtherAlias, otherPropertyName );
|
||||
parameters.addWhereWithFunction(
|
||||
enversService.getConfig(),
|
||||
aliasToEntityNameMap,
|
||||
function,
|
||||
op,
|
||||
effectiveOtherAlias,
|
||||
otherPropertyName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,14 @@ public class SimpleFunctionAuditExpression implements AuditCriterion {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addToQuery(EnversService enversService, AuditReaderImplementor versionsReader,
|
||||
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder qb, Parameters parameters) {
|
||||
parameters.addWhereWithFunction( enversService.getConfig(), function, op, value );
|
||||
public void addToQuery(
|
||||
EnversService enversService,
|
||||
AuditReaderImplementor versionsReader,
|
||||
Map<String, String> aliasToEntityNameMap,
|
||||
String baseAlias,
|
||||
QueryBuilder qb,
|
||||
Parameters parameters) {
|
||||
parameters.addWhereWithFunction( enversService.getConfig(), aliasToEntityNameMap, function, op, value );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -153,4 +153,12 @@ public class AuditFunctionQueryTest extends BaseEnversJPAFunctionalTestCase {
|
|||
assertEquals( "Expected the entity to be returned", testEntity1.getId(), entity.getId() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionOnIdProperty() {
|
||||
TestEntity entity = (TestEntity) getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||
.add( AuditEntity.function( "str", AuditEntity.id() ).like( "%1%" ) ).getSingleResult();
|
||||
assertNotNull( "Expected the entity to be returned", entity );
|
||||
assertEquals( "Expected the entity to be returned", testEntity1.getId(), entity.getId() );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue