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.
|
* Add where clause with a function call on the left and a scalar value on the right.
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @param configuration the configuration.
|
||||||
|
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||||
* @param function the function.
|
* @param function the function.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
* @param value the scalar value.
|
* @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();
|
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 );
|
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.
|
* Add a where clause with a function call on the left and an optionally aliased property on the right.
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @param configuration the configuration.
|
||||||
|
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||||
* @param function the function.
|
* @param function the function.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
* @param aliasRight the optional alias of the right property, may be {@literal null}
|
* @param aliasRight the optional alias of the right property, may be {@literal null}
|
||||||
* @param right the property.
|
* @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();
|
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( ' ' );
|
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.
|
* Adds a where clause with a left (optionally aliased) property and a function call on the right side.
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @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 aliasLeft the optional alias of the left property, may be {@literal null}
|
||||||
* @param left the property.
|
* @param left the property.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
* @param function the function.
|
* @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();
|
final StringBuilder expression = new StringBuilder();
|
||||||
|
|
||||||
if ( aliasLeft != null ) {
|
if ( aliasLeft != null ) {
|
||||||
|
@ -378,7 +414,15 @@ public class Parameters {
|
||||||
|
|
||||||
expression.append( ' ' ).append( op ).append( ' ' );
|
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() );
|
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.
|
* Adds a where clause with a function call on both the left and right of the predicate.
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @param configuration the configuration.
|
||||||
|
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||||
* @param left the left-side function.
|
* @param left the left-side function.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
* @param right the right-side function.
|
* @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();
|
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( ' ' );
|
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() );
|
expressions.add( expression.toString() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,18 +12,23 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.JoinType;
|
import jakarta.persistence.criteria.JoinType;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.configuration.Configuration;
|
import org.hibernate.envers.configuration.Configuration;
|
||||||
import org.hibernate.envers.function.OrderByFragmentFunction;
|
import org.hibernate.envers.function.OrderByFragmentFunction;
|
||||||
import org.hibernate.envers.internal.entities.RevisionTypeType;
|
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.MutableInteger;
|
||||||
import org.hibernate.envers.internal.tools.StringTools;
|
import org.hibernate.envers.internal.tools.StringTools;
|
||||||
import org.hibernate.envers.internal.tools.Triple;
|
import org.hibernate.envers.internal.tools.Triple;
|
||||||
import org.hibernate.envers.query.criteria.AuditFunction;
|
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.query.criteria.AuditProperty;
|
||||||
import org.hibernate.envers.tools.Pair;
|
import org.hibernate.envers.tools.Pair;
|
||||||
import org.hibernate.query.Query;
|
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();
|
final StringBuilder expression = new StringBuilder();
|
||||||
appendFunctionArgument( configuration, paramCounter, projectionQueryParamValues, alias, expression, function );
|
appendFunctionArgument(
|
||||||
|
configuration,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
paramCounter,
|
||||||
|
projectionQueryParamValues,
|
||||||
|
alias,
|
||||||
|
expression,
|
||||||
|
function
|
||||||
|
);
|
||||||
projections.add( expression.toString() );
|
projections.add( expression.toString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void appendFunctionArgument(
|
protected static void appendFunctionArgument(
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
MutableInteger paramCounter,
|
MutableInteger paramCounter,
|
||||||
Map<String, Object> queryParamValues,
|
Map<String, Object> queryParamValues,
|
||||||
String alias,
|
String alias,
|
||||||
|
@ -235,11 +249,42 @@ public class QueryBuilder {
|
||||||
if ( !first ) {
|
if ( !first ) {
|
||||||
expression.append( ',' );
|
expression.append( ',' );
|
||||||
}
|
}
|
||||||
appendFunctionArgument( configuration, paramCounter, queryParamValues, alias, expression, innerArg );
|
appendFunctionArgument(
|
||||||
|
configuration,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
paramCounter,
|
||||||
|
queryParamValues,
|
||||||
|
alias,
|
||||||
|
expression,
|
||||||
|
innerArg
|
||||||
|
);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
expression.append( ')' );
|
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 ) {
|
else if ( argument instanceof AuditProperty ) {
|
||||||
AuditProperty<?> property = (AuditProperty<?>) argument;
|
AuditProperty<?> property = (AuditProperty<?>) argument;
|
||||||
String propertyAlias = property.getAlias( alias );
|
String propertyAlias = property.getAlias( alias );
|
||||||
|
|
|
@ -55,6 +55,20 @@ public class AuditFunction implements AuditProjection {
|
||||||
return new SimpleFunctionAuditExpression( this, value, "<>" );
|
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
|
* Apply a "greater than" constraint
|
||||||
*/
|
*/
|
||||||
|
@ -222,9 +236,13 @@ public class AuditFunction implements AuditProjection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addProjectionToQuery(EnversService enversService, AuditReaderImplementor auditReader,
|
public void addProjectionToQuery(
|
||||||
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder queryBuilder) {
|
EnversService enversService,
|
||||||
queryBuilder.addProjection( enversService.getConfig(), this );
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder) {
|
||||||
|
queryBuilder.addProjection( enversService.getConfig(), aliasToEntityNameMap, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -43,6 +43,12 @@ public class FunctionFunctionAuditExpression implements AuditCriterion {
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder queryBuilder,
|
QueryBuilder queryBuilder,
|
||||||
Parameters parameters) {
|
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,
|
entityName,
|
||||||
propertyNameGetter );
|
propertyNameGetter );
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
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 ) ) {
|
if ( enversService.getEntitiesConfigurations().isVersioned( otherEntityName ) ) {
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, otherEntityName, otherPropertyName );
|
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
|
@Override
|
||||||
public void addToQuery(EnversService enversService, AuditReaderImplementor versionsReader,
|
public void addToQuery(
|
||||||
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder qb, Parameters parameters) {
|
EnversService enversService,
|
||||||
parameters.addWhereWithFunction( enversService.getConfig(), function, op, value );
|
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() );
|
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