HHH-11452 Extended audit query API to specify the use of scalar
functions.
This commit is contained in:
parent
bb09222102
commit
640bd85975
|
@ -11,8 +11,10 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.envers.configuration.Configuration;
|
||||||
import org.hibernate.envers.internal.tools.MutableBoolean;
|
import org.hibernate.envers.internal.tools.MutableBoolean;
|
||||||
import org.hibernate.envers.internal.tools.MutableInteger;
|
import org.hibernate.envers.internal.tools.MutableInteger;
|
||||||
|
import org.hibernate.envers.query.criteria.AuditFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters of a query, built using {@link QueryBuilder}.
|
* Parameters of a query, built using {@link QueryBuilder}.
|
||||||
|
@ -311,6 +313,96 @@ 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 function the function.
|
||||||
|
* @param op the operator.
|
||||||
|
* @param value the scalar value.
|
||||||
|
*/
|
||||||
|
public void addWhereWithFunction(Configuration configuration, AuditFunction function, String op, Object value) {
|
||||||
|
final StringBuilder expression = new StringBuilder();
|
||||||
|
|
||||||
|
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, function );
|
||||||
|
|
||||||
|
expression.append( ' ' ).append( op );
|
||||||
|
|
||||||
|
String queryParam = generateQueryParam();
|
||||||
|
localQueryParamValues.put( queryParam, value );
|
||||||
|
expression.append( ' ' ).append( ':' ).append( queryParam );
|
||||||
|
|
||||||
|
expressions.add( expression.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a where clause with a function call on the left and an optionally aliased property on the right.
|
||||||
|
*
|
||||||
|
* @param configuration the configuration.
|
||||||
|
* @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) {
|
||||||
|
final StringBuilder expression = new StringBuilder();
|
||||||
|
|
||||||
|
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, function );
|
||||||
|
|
||||||
|
expression.append( ' ' ).append( op ).append( ' ' );
|
||||||
|
|
||||||
|
if ( aliasRight != null ) {
|
||||||
|
expression.append( aliasRight ).append( '.' );
|
||||||
|
}
|
||||||
|
expression.append( right );
|
||||||
|
|
||||||
|
expressions.add( expression.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a where clause with a left (optionally aliased) property and a function call on the right side.
|
||||||
|
*
|
||||||
|
* @param configuration the configuration.
|
||||||
|
* @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) {
|
||||||
|
final StringBuilder expression = new StringBuilder();
|
||||||
|
|
||||||
|
if ( aliasLeft != null ) {
|
||||||
|
expression.append( aliasLeft ).append( '.' );
|
||||||
|
}
|
||||||
|
expression.append( left );
|
||||||
|
|
||||||
|
expression.append( ' ' ).append( op ).append( ' ' );
|
||||||
|
|
||||||
|
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, function );
|
||||||
|
|
||||||
|
expressions.add( expression.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a where clause with a function call on both the left and right of the predicate.
|
||||||
|
*
|
||||||
|
* @param configuration the configuration.
|
||||||
|
* @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) {
|
||||||
|
final StringBuilder expression = new StringBuilder();
|
||||||
|
|
||||||
|
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, left );
|
||||||
|
|
||||||
|
expression.append( ' ' ).append( op ).append( ' ' );
|
||||||
|
|
||||||
|
QueryBuilder.appendFunctionArgument( configuration, queryParamCounter, localQueryParamValues, alias, expression, right );
|
||||||
|
|
||||||
|
expressions.add( expression.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
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( " " );
|
||||||
|
|
|
@ -17,11 +17,14 @@ import jakarta.persistence.criteria.JoinType;
|
||||||
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.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.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.AuditProperty;
|
||||||
import org.hibernate.envers.tools.Pair;
|
import org.hibernate.envers.tools.Pair;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.internal.QueryLiteralHelper;
|
import org.hibernate.query.internal.QueryLiteralHelper;
|
||||||
|
@ -62,6 +65,10 @@ public class QueryBuilder {
|
||||||
* A list of complete projection definitions: either a sole property name, or a function(property name).
|
* A list of complete projection definitions: either a sole property name, or a function(property name).
|
||||||
*/
|
*/
|
||||||
private final List<String> projections;
|
private final List<String> projections;
|
||||||
|
/**
|
||||||
|
* Values of parameters used in projections.
|
||||||
|
*/
|
||||||
|
private final Map<String, Object> projectionQueryParamValues;
|
||||||
|
|
||||||
private final List<Pair<String, String>> orderFragments;
|
private final List<Pair<String, String>> orderFragments;
|
||||||
|
|
||||||
|
@ -100,6 +107,7 @@ public class QueryBuilder {
|
||||||
froms = new ArrayList<>();
|
froms = new ArrayList<>();
|
||||||
orders = new ArrayList<>();
|
orders = new ArrayList<>();
|
||||||
projections = new ArrayList<>();
|
projections = new ArrayList<>();
|
||||||
|
projectionQueryParamValues = new HashMap<>();
|
||||||
orderFragments = new ArrayList<>();
|
orderFragments = new ArrayList<>();
|
||||||
|
|
||||||
addFrom( entityName, alias, true );
|
addFrom( entityName, alias, true );
|
||||||
|
@ -120,6 +128,7 @@ public class QueryBuilder {
|
||||||
froms = new ArrayList<>( other.froms );
|
froms = new ArrayList<>( other.froms );
|
||||||
orders = new ArrayList<>( other.orders );
|
orders = new ArrayList<>( other.orders );
|
||||||
projections = new ArrayList<>( other.projections );
|
projections = new ArrayList<>( other.projections );
|
||||||
|
projectionQueryParamValues = new HashMap<>( other.projectionQueryParamValues );
|
||||||
orderFragments = new ArrayList<>( other.orderFragments );
|
orderFragments = new ArrayList<>( other.orderFragments );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +214,48 @@ public class QueryBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addProjection(Configuration configuration, AuditFunction function) {
|
||||||
|
final StringBuilder expression = new StringBuilder();
|
||||||
|
appendFunctionArgument( configuration, paramCounter, projectionQueryParamValues, alias, expression, function );
|
||||||
|
projections.add( expression.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void appendFunctionArgument(
|
||||||
|
Configuration configuration,
|
||||||
|
MutableInteger paramCounter,
|
||||||
|
Map<String, Object> queryParamValues,
|
||||||
|
String alias,
|
||||||
|
StringBuilder expression,
|
||||||
|
Object argument) {
|
||||||
|
if ( argument instanceof AuditFunction ) {
|
||||||
|
AuditFunction function = (AuditFunction) argument;
|
||||||
|
expression.append( function.getFunction() ).append( '(' );
|
||||||
|
boolean first = true;
|
||||||
|
for ( final Object innerArg : function.getArguments() ) {
|
||||||
|
if ( !first ) {
|
||||||
|
expression.append( ',' );
|
||||||
|
}
|
||||||
|
appendFunctionArgument( configuration, paramCounter, queryParamValues, alias, expression, innerArg );
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
expression.append( ')' );
|
||||||
|
}
|
||||||
|
else if ( argument instanceof AuditProperty ) {
|
||||||
|
AuditProperty<?> property = (AuditProperty<?>) argument;
|
||||||
|
String propertyAlias = property.getAlias( alias );
|
||||||
|
if ( propertyAlias != null ) {
|
||||||
|
expression.append( propertyAlias ).append( '.' );
|
||||||
|
}
|
||||||
|
String propertyName = property.getPropertyNameGetter().get( configuration );
|
||||||
|
expression.append( propertyName );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String queryParam = "_p" + paramCounter.getAndIncrease();
|
||||||
|
queryParamValues.put( queryParam, argument );
|
||||||
|
expression.append( ':' ).append( queryParam );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the given query, appending results to the given string buffer, and adding all query parameter values
|
* Builds the given query, appending results to the given string buffer, and adding all query parameter values
|
||||||
* that are used to the map provided.
|
* that are used to the map provided.
|
||||||
|
@ -222,6 +273,7 @@ public class QueryBuilder {
|
||||||
// all aliases separated with commas
|
// all aliases separated with commas
|
||||||
StringTools.append( sb, getSelectAliasList().iterator(), ", " );
|
StringTools.append( sb, getSelectAliasList().iterator(), ", " );
|
||||||
}
|
}
|
||||||
|
queryParamValues.putAll( projectionQueryParamValues );
|
||||||
sb.append( " from " );
|
sb.append( " from " );
|
||||||
// all from entities with aliases
|
// all from entities with aliases
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
|
|
|
@ -6,10 +6,15 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.query;
|
package org.hibernate.envers.query;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
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;
|
||||||
|
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;
|
||||||
|
@ -176,4 +181,30 @@ public class AuditEntity {
|
||||||
public static AuditProjection selectEntity(boolean distinct) {
|
public static AuditProjection selectEntity(boolean distinct) {
|
||||||
return new EntityAuditProjection( null, distinct );
|
return new EntityAuditProjection( null, distinct );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create restrictions or projections using a function.
|
||||||
|
* <p>
|
||||||
|
* Examples:
|
||||||
|
* <ul>
|
||||||
|
* <li>AuditEntity.function("upper", AuditEntity.property("prop"))</li>
|
||||||
|
* <li>AuditEntity.function("substring", AuditEntity.property("prop"), 3, 2)</li>
|
||||||
|
* <li>AuditEntity.function("concat", AuditEntity.function("upper", AuditEntity.property("prop1")),
|
||||||
|
* AuditEntity.function("substring", AuditEntity.property("prop2"), 1, 2))</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param function the name of the function
|
||||||
|
* @param arguments the arguments of the function. A function argument can either be
|
||||||
|
* <ul>
|
||||||
|
* <li>a primitive value like a Number or a String</li>
|
||||||
|
* <li>an AuditProperty (see {@link #property(String)})</li>
|
||||||
|
* <li>an other AuditFunction</li>
|
||||||
|
* </ul>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static AuditFunction function(final String function, final Object... arguments) {
|
||||||
|
List<Object> argumentList = new ArrayList<>();
|
||||||
|
Collections.addAll( argumentList, arguments );
|
||||||
|
return new AuditFunction( function, argumentList );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,241 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.FunctionFunctionAuditExpression;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.PropertyFunctionAuditExpression;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.SimpleFunctionAuditExpression;
|
||||||
|
import org.hibernate.envers.query.projection.AuditProjection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create restrictions or projections using a function.
|
||||||
|
*
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class AuditFunction implements AuditProjection {
|
||||||
|
|
||||||
|
private final String function;
|
||||||
|
private final List<Object> arguments;
|
||||||
|
|
||||||
|
public AuditFunction(String function, List<Object> arguments) {
|
||||||
|
this.function = function;
|
||||||
|
this.arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFunction() {
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Object> getArguments() {
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an "equal" constraint
|
||||||
|
*/
|
||||||
|
public AuditCriterion eq(Object value) {
|
||||||
|
return new SimpleFunctionAuditExpression( this, value, "=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "not equal" constraint
|
||||||
|
*/
|
||||||
|
public AuditCriterion ne(Object value) {
|
||||||
|
return new SimpleFunctionAuditExpression( this, value, "<>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than" constraint
|
||||||
|
*/
|
||||||
|
public AuditCriterion gt(Object value) {
|
||||||
|
return new SimpleFunctionAuditExpression( this, value, ">" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than" constraint
|
||||||
|
*/
|
||||||
|
public AuditCriterion lt(Object value) {
|
||||||
|
return new SimpleFunctionAuditExpression( this, value, "<" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than or equal" constraint
|
||||||
|
*/
|
||||||
|
public AuditCriterion le(Object value) {
|
||||||
|
return new SimpleFunctionAuditExpression( this, value, "<=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than or equal" constraint
|
||||||
|
*/
|
||||||
|
public AuditCriterion ge(Object value) {
|
||||||
|
return new SimpleFunctionAuditExpression( this, value, ">=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an "equal" constraint to a property
|
||||||
|
*/
|
||||||
|
public AuditCriterion eqProperty(String propertyName) {
|
||||||
|
return eqProperty( null, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an "equal" constraint to a property
|
||||||
|
*
|
||||||
|
* @param alias the alias of the entity which owns the property.
|
||||||
|
*/
|
||||||
|
public AuditCriterion eqProperty(String alias, String propertyName) {
|
||||||
|
return new PropertyFunctionAuditExpression( this, alias, propertyName, "=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "not equal" constraint to a property
|
||||||
|
*/
|
||||||
|
public AuditCriterion neProperty(String propertyName) {
|
||||||
|
return neProperty( null, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "not equal" constraint to a property
|
||||||
|
*
|
||||||
|
* @param alias the alias of the entity which owns the property.
|
||||||
|
*/
|
||||||
|
public AuditCriterion neProperty(String alias, String propertyName) {
|
||||||
|
return new PropertyFunctionAuditExpression( this, alias, propertyName, "<>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than" constraint to a property
|
||||||
|
*/
|
||||||
|
public AuditCriterion ltProperty(String propertyName) {
|
||||||
|
return ltProperty( null, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than" constraint to a property
|
||||||
|
*
|
||||||
|
* @param alias the alias of the entity which owns the property.
|
||||||
|
*/
|
||||||
|
public AuditCriterion ltProperty(String alias, String propertyName) {
|
||||||
|
return new PropertyFunctionAuditExpression( this, alias, propertyName, "<" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than or equal" constraint to a property
|
||||||
|
*/
|
||||||
|
public AuditCriterion leProperty(String propertyName) {
|
||||||
|
return leProperty( null, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than or equal" constraint to a property
|
||||||
|
*
|
||||||
|
* @param alias the alias of the entity which owns the property.
|
||||||
|
*/
|
||||||
|
public AuditCriterion leProperty(String alias, String propertyName) {
|
||||||
|
return new PropertyFunctionAuditExpression( this, alias, propertyName, "<=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than" constraint to a property
|
||||||
|
*/
|
||||||
|
public AuditCriterion gtProperty(String propertyName) {
|
||||||
|
return gtProperty( null, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than" constraint to a property
|
||||||
|
*
|
||||||
|
* @param alias the alias of the entity which owns the property.
|
||||||
|
*/
|
||||||
|
public AuditCriterion gtProperty(String alias, String propertyName) {
|
||||||
|
return new PropertyFunctionAuditExpression( this, alias, propertyName, ">" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than or equal" constraint to a property
|
||||||
|
*/
|
||||||
|
public AuditCriterion geProperty(String propertyName) {
|
||||||
|
return geProperty( null, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than or equal" constraint to a property
|
||||||
|
*
|
||||||
|
* @param alias the alias of the entity which owns the property.
|
||||||
|
*/
|
||||||
|
public AuditCriterion geProperty(String alias, String propertyName) {
|
||||||
|
return new PropertyFunctionAuditExpression( this, alias, propertyName, ">=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an "equal" constraint to another function
|
||||||
|
*/
|
||||||
|
public AuditCriterion eqFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionFunctionAuditExpression( this, otherFunction, "=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "not equal" constraint to another function
|
||||||
|
*/
|
||||||
|
public AuditCriterion neFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionFunctionAuditExpression( this, otherFunction, "<>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than" constraint to another function
|
||||||
|
*/
|
||||||
|
public AuditCriterion ltFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionFunctionAuditExpression( this, otherFunction, "<" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than or equal" constraint to another function
|
||||||
|
*/
|
||||||
|
public AuditCriterion leFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionFunctionAuditExpression( this, otherFunction, "<=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than" constraint to another function
|
||||||
|
*/
|
||||||
|
public AuditCriterion gtFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionFunctionAuditExpression( this, otherFunction, ">" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than or equal" constraint to another function
|
||||||
|
*/
|
||||||
|
public AuditCriterion geFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionFunctionAuditExpression( this, otherFunction, ">=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addProjectionToQuery(EnversService enversService, AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder queryBuilder) {
|
||||||
|
queryBuilder.addProjection( enversService.getConfig(), this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertQueryResult(EnversService enversService, EntityInstantiator entityInstantiator,
|
||||||
|
String entityName, Number revision, Object value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAlias(String baseAlias) {
|
||||||
|
return baseAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,11 +7,15 @@
|
||||||
package org.hibernate.envers.query.criteria;
|
package org.hibernate.envers.query.criteria;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.configuration.Configuration;
|
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
import org.hibernate.envers.query.criteria.internal.BetweenAuditExpression;
|
import org.hibernate.envers.query.criteria.internal.BetweenAuditExpression;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.CriteriaTools;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.FunctionPropertyAuditExpression;
|
||||||
import org.hibernate.envers.query.criteria.internal.IlikeAuditExpression;
|
import org.hibernate.envers.query.criteria.internal.IlikeAuditExpression;
|
||||||
import org.hibernate.envers.query.criteria.internal.InAuditExpression;
|
import org.hibernate.envers.query.criteria.internal.InAuditExpression;
|
||||||
import org.hibernate.envers.query.criteria.internal.NotNullAuditExpression;
|
import org.hibernate.envers.query.criteria.internal.NotNullAuditExpression;
|
||||||
|
@ -42,6 +46,15 @@ public class AuditProperty<T> implements AuditProjection {
|
||||||
this.propertyNameGetter = propertyNameGetter;
|
this.propertyNameGetter = propertyNameGetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAlias(String baseAlias) {
|
||||||
|
return alias == null ? baseAlias : alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyNameGetter getPropertyNameGetter() {
|
||||||
|
return propertyNameGetter;
|
||||||
|
}
|
||||||
|
|
||||||
public AuditCriterion hasChanged() {
|
public AuditCriterion hasChanged() {
|
||||||
return new SimpleAuditExpression( alias, new ModifiedFlagPropertyName( propertyNameGetter ), true, "=" );
|
return new SimpleAuditExpression( alias, new ModifiedFlagPropertyName( propertyNameGetter ), true, "=" );
|
||||||
}
|
}
|
||||||
|
@ -280,6 +293,48 @@ public class AuditProperty<T> implements AuditProjection {
|
||||||
return new PropertyAuditExpression( alias, propertyNameGetter, otherAlias, otherPropertyName, ">=" );
|
return new PropertyAuditExpression( alias, propertyNameGetter, otherAlias, otherPropertyName, ">=" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an "equal" constraint to a function
|
||||||
|
*/
|
||||||
|
public AuditCriterion eqFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionPropertyAuditExpression( alias, propertyNameGetter, otherFunction, "=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "not equal" constraint to a function
|
||||||
|
*/
|
||||||
|
public AuditCriterion neFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionPropertyAuditExpression( alias, propertyNameGetter, otherFunction, "<>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than" constraint to a function
|
||||||
|
*/
|
||||||
|
public AuditCriterion ltFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionPropertyAuditExpression( alias, propertyNameGetter, otherFunction, "<" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "less than or equal" constraint to a function
|
||||||
|
*/
|
||||||
|
public AuditCriterion leFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionPropertyAuditExpression( alias, propertyNameGetter, otherFunction, "<=" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than" constraint to a function
|
||||||
|
*/
|
||||||
|
public AuditCriterion gtFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionPropertyAuditExpression( alias, propertyNameGetter, otherFunction, ">" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a "greater than or equal" constraint to a function
|
||||||
|
*/
|
||||||
|
public AuditCriterion geFunction(AuditFunction otherFunction) {
|
||||||
|
return new FunctionPropertyAuditExpression( alias, propertyNameGetter, otherFunction, ">=" );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply an "is not null" constraint to the another property
|
* Apply an "is not null" constraint to the another property
|
||||||
*/
|
*/
|
||||||
|
@ -349,16 +404,21 @@ public class AuditProperty<T> implements AuditProjection {
|
||||||
|
|
||||||
// Projection on this property
|
// Projection on this property
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @deprecated since 6.0, use {@link #getData(Configuration)} instead.
|
public void addProjectionToQuery(EnversService enversService, AuditReaderImplementor auditReader,
|
||||||
*/
|
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder queryBuilder) {
|
||||||
@Deprecated
|
String projectionEntityAlias = getAlias( baseAlias );
|
||||||
public ProjectionData getData(EnversService enversService) {
|
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
||||||
return new ProjectionData( null, alias, propertyNameGetter.get( enversService.getConfig() ), false );
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
}
|
enversService,
|
||||||
|
auditReader,
|
||||||
public ProjectionData getData(Configuration configuration) {
|
projectionEntityName,
|
||||||
return new ProjectionData( null, alias, propertyNameGetter.get( configuration ), false );
|
propertyNameGetter );
|
||||||
|
queryBuilder.addProjection(
|
||||||
|
null,
|
||||||
|
projectionEntityAlias,
|
||||||
|
propertyName,
|
||||||
|
false );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order
|
// Order
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import org.hibernate.envers.query.criteria.AuditFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An audit query criterion that defines a predicate where both sides are a function.
|
||||||
|
*
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class FunctionFunctionAuditExpression implements AuditCriterion {
|
||||||
|
|
||||||
|
private AuditFunction leftFunction;
|
||||||
|
private AuditFunction rightFunction;
|
||||||
|
private String op;
|
||||||
|
|
||||||
|
public FunctionFunctionAuditExpression(
|
||||||
|
AuditFunction leftFunction,
|
||||||
|
AuditFunction rightFunction,
|
||||||
|
String op) {
|
||||||
|
this.leftFunction = leftFunction;
|
||||||
|
this.rightFunction = rightFunction;
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToQuery(
|
||||||
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder,
|
||||||
|
Parameters parameters) {
|
||||||
|
parameters.addWhereWithFunction( enversService.getConfig(), leftFunction, op, rightFunction );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import org.hibernate.envers.query.criteria.AuditFunction;
|
||||||
|
import org.hibernate.envers.query.internal.property.PropertyNameGetter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An audit query criterion that defines a predicate that is a comparison between a function
|
||||||
|
* and an audit property expression.
|
||||||
|
*
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class FunctionPropertyAuditExpression implements AuditCriterion {
|
||||||
|
|
||||||
|
private String alias;
|
||||||
|
private PropertyNameGetter propertyNameGetter;
|
||||||
|
private AuditFunction function;
|
||||||
|
private String op;
|
||||||
|
|
||||||
|
public FunctionPropertyAuditExpression(
|
||||||
|
String alias,
|
||||||
|
PropertyNameGetter propertyNameGetter,
|
||||||
|
AuditFunction function,
|
||||||
|
String op) {
|
||||||
|
this.alias = alias;
|
||||||
|
this.propertyNameGetter = propertyNameGetter;
|
||||||
|
this.function = function;
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToQuery(
|
||||||
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder,
|
||||||
|
Parameters parameters) {
|
||||||
|
String effectiveAlias = alias == null ? baseAlias : alias;
|
||||||
|
String entityName = aliasToEntityNameMap.get( effectiveAlias );
|
||||||
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
enversService,
|
||||||
|
auditReader,
|
||||||
|
entityName,
|
||||||
|
propertyNameGetter );
|
||||||
|
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
||||||
|
parameters.addWhereWithFunction( enversService.getConfig(), effectiveAlias, propertyName, op, function );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import org.hibernate.envers.query.criteria.AuditFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An audit query criterion where a function is compared to a property.
|
||||||
|
*
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class PropertyFunctionAuditExpression implements AuditCriterion {
|
||||||
|
|
||||||
|
private AuditFunction function;
|
||||||
|
private String otherAlias;
|
||||||
|
private String otherPropertyName;
|
||||||
|
private String op;
|
||||||
|
|
||||||
|
public PropertyFunctionAuditExpression(
|
||||||
|
AuditFunction function,
|
||||||
|
String otherAlias,
|
||||||
|
String otherPropertyName,
|
||||||
|
String op) {
|
||||||
|
this.function = function;
|
||||||
|
this.otherAlias = otherAlias;
|
||||||
|
this.otherPropertyName = otherPropertyName;
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToQuery(
|
||||||
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder,
|
||||||
|
Parameters parameters) {
|
||||||
|
String effectiveOtherAlias = otherAlias == null ? baseAlias : otherAlias;
|
||||||
|
String otherEntityName = aliasToEntityNameMap.get( effectiveOtherAlias );
|
||||||
|
/*
|
||||||
|
* Check that the other property name is not a relation. However, we can only do this for audited entities. If
|
||||||
|
* the other property belongs to a non-audited entity, we have to skip this check.
|
||||||
|
*/
|
||||||
|
if ( enversService.getEntitiesConfigurations().isVersioned( otherEntityName ) ) {
|
||||||
|
CriteriaTools.checkPropertyNotARelation( enversService, otherEntityName, otherPropertyName );
|
||||||
|
}
|
||||||
|
parameters.addWhereWithFunction( enversService.getConfig(), function, op, effectiveOtherAlias, otherPropertyName );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import org.hibernate.envers.query.criteria.AuditFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An audit query criterion that compares a function call with a scalar value.
|
||||||
|
*
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class SimpleFunctionAuditExpression implements AuditCriterion {
|
||||||
|
|
||||||
|
private AuditFunction function;
|
||||||
|
private Object value;
|
||||||
|
private String op;
|
||||||
|
|
||||||
|
public SimpleFunctionAuditExpression(AuditFunction function, Object value, String op) {
|
||||||
|
this.function = function;
|
||||||
|
this.value = value;
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -135,22 +135,10 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
// Projection and order
|
// Projection and order
|
||||||
|
|
||||||
public AuditQuery addProjection(AuditProjection projection) {
|
public AuditQuery addProjection(AuditProjection projection) {
|
||||||
AuditProjection.ProjectionData projectionData = projection.getData( enversService.getConfig() );
|
String projectionEntityAlias = projection.getAlias( REFERENCED_ENTITY_ALIAS );
|
||||||
String projectionEntityAlias = projectionData.getAlias( REFERENCED_ENTITY_ALIAS );
|
|
||||||
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
||||||
registerProjection( projectionEntityName, projection );
|
registerProjection( projectionEntityName, projection );
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
projection.addProjectionToQuery( enversService, versionsReader, aliasToEntityNameMap, REFERENCED_ENTITY_ALIAS, qb );
|
||||||
enversService,
|
|
||||||
versionsReader,
|
|
||||||
projectionEntityName,
|
|
||||||
projectionData.getPropertyName()
|
|
||||||
);
|
|
||||||
qb.addProjection(
|
|
||||||
projectionData.getFunction(),
|
|
||||||
projectionEntityAlias,
|
|
||||||
propertyName,
|
|
||||||
projectionData.isDistinct()
|
|
||||||
);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,22 +159,10 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuditAssociationQueryImpl<Q> addProjection(AuditProjection projection) {
|
public AuditAssociationQueryImpl<Q> addProjection(AuditProjection projection) {
|
||||||
AuditProjection.ProjectionData projectionData = projection.getData( enversService.getConfig() );
|
String projectionEntityAlias = projection.getAlias( alias );
|
||||||
String projectionEntityAlias = projectionData.getAlias( alias );
|
|
||||||
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
|
||||||
enversService,
|
|
||||||
auditReader,
|
|
||||||
projectionEntityName,
|
|
||||||
projectionData.getPropertyName()
|
|
||||||
);
|
|
||||||
queryBuilder.addProjection(
|
|
||||||
projectionData.getFunction(),
|
|
||||||
projectionEntityAlias,
|
|
||||||
propertyName,
|
|
||||||
projectionData.isDistinct()
|
|
||||||
);
|
|
||||||
registerProjection( projectionEntityName, projection );
|
registerProjection( projectionEntityName, projection );
|
||||||
|
projection.addProjectionToQuery( enversService, auditReader, aliasToEntityNameMap, alias, queryBuilder );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.query.projection;
|
package org.hibernate.envers.query.projection;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.configuration.Configuration;
|
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
@ -17,10 +20,28 @@ import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
public interface AuditProjection {
|
public interface AuditProjection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param configuration the configuration
|
* Adds an audit projection to the specified query.
|
||||||
* @return get the project data
|
*
|
||||||
|
* @param enversService the Envers service
|
||||||
|
* @param auditReader the audit reader implementor
|
||||||
|
* @param aliasToEntityNameMap the entity name alias map
|
||||||
|
* @param baseAlias the base alias, if one is specified; may be {@literal null}
|
||||||
|
* @param queryBuilder the query builder
|
||||||
*/
|
*/
|
||||||
ProjectionData getData(Configuration configuration);
|
void addProjectionToQuery(
|
||||||
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the alias associated with the audit projection.
|
||||||
|
*
|
||||||
|
* @param baseAlias the base alias if one exists; may be {@literal null}
|
||||||
|
* @return the alias
|
||||||
|
*/
|
||||||
|
String getAlias(String baseAlias);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param enversService the Envers service
|
* @param enversService the Envers service
|
||||||
|
@ -38,35 +59,4 @@ public interface AuditProjection {
|
||||||
final Object value
|
final Object value
|
||||||
);
|
);
|
||||||
|
|
||||||
class ProjectionData {
|
|
||||||
|
|
||||||
private final String function;
|
|
||||||
private final String alias;
|
|
||||||
private final String propertyName;
|
|
||||||
private final boolean distinct;
|
|
||||||
|
|
||||||
public ProjectionData(String function, String alias, String propertyName, boolean distinct) {
|
|
||||||
this.function = function;
|
|
||||||
this.alias = alias;
|
|
||||||
this.propertyName = propertyName;
|
|
||||||
this.distinct = distinct;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFunction() {
|
|
||||||
return function;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAlias(String baseAlias) {
|
|
||||||
return alias == null ? baseAlias : alias;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPropertyName() {
|
|
||||||
return propertyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDistinct() {
|
|
||||||
return distinct;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@ package org.hibernate.envers.query.projection.internal;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.configuration.Configuration;
|
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
import org.hibernate.envers.query.projection.AuditProjection;
|
import org.hibernate.envers.query.projection.AuditProjection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,9 +29,19 @@ public class EntityAuditProjection implements AuditProjection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProjectionData getData(Configuration configuration) {
|
public String getAlias(String baseAlias) {
|
||||||
// no property is selected, instead the whole entity (alias) is selected
|
return alias == null ? baseAlias : alias;
|
||||||
return new ProjectionData( null, alias, null, distinct );
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addProjectionToQuery(EnversService enversService, AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder queryBuilder) {
|
||||||
|
String projectionEntityAlias = getAlias( baseAlias );
|
||||||
|
queryBuilder.addProjection(
|
||||||
|
null,
|
||||||
|
projectionEntityAlias,
|
||||||
|
null,
|
||||||
|
distinct );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,9 +6,13 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.query.projection.internal;
|
package org.hibernate.envers.query.projection.internal;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.configuration.Configuration;
|
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.CriteriaTools;
|
||||||
import org.hibernate.envers.query.internal.property.PropertyNameGetter;
|
import org.hibernate.envers.query.internal.property.PropertyNameGetter;
|
||||||
import org.hibernate.envers.query.projection.AuditProjection;
|
import org.hibernate.envers.query.projection.AuditProjection;
|
||||||
|
|
||||||
|
@ -30,10 +34,29 @@ public class PropertyAuditProjection implements AuditProjection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProjectionData getData(Configuration configuration) {
|
public String getAlias(String baseAlias) {
|
||||||
String propertyName = propertyNameGetter.get( configuration );
|
return alias == null ? baseAlias : alias;
|
||||||
|
}
|
||||||
|
|
||||||
return new ProjectionData( function, alias, propertyName, distinct );
|
@Override
|
||||||
|
public void addProjectionToQuery(
|
||||||
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder) {
|
||||||
|
String projectionEntityAlias = getAlias( baseAlias );
|
||||||
|
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
||||||
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
enversService,
|
||||||
|
auditReader,
|
||||||
|
projectionEntityName,
|
||||||
|
propertyNameGetter );
|
||||||
|
queryBuilder.addProjection(
|
||||||
|
function,
|
||||||
|
projectionEntityAlias,
|
||||||
|
propertyName,
|
||||||
|
distinct );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* 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 static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
|
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 AuditFunctionQueryTest extends BaseEnversJPAFunctionalTestCase {
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Audited
|
||||||
|
public static class TestEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String string1;
|
||||||
|
private String string2;
|
||||||
|
private Integer int1;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString1() {
|
||||||
|
return string1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setString1(String string1) {
|
||||||
|
this.string1 = string1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString2() {
|
||||||
|
return string2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getInt1() {
|
||||||
|
return int1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInt1(Integer int1) {
|
||||||
|
this.int1 = int1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setString2(String string2) {
|
||||||
|
this.string2 = string2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestEntity testEntity1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[]{ TestEntity.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Priority(10)
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
testEntity1 = new TestEntity();
|
||||||
|
testEntity1.setId( 1L );
|
||||||
|
testEntity1.setString1( "abcdef" );
|
||||||
|
testEntity1.setString2( "42 - the truth" );
|
||||||
|
testEntity1.setInt1( 42 );
|
||||||
|
em.persist( testEntity1 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProjectionWithPropertyArgument() {
|
||||||
|
Object actual = getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||||
|
.addProjection( AuditEntity.function( "upper", AuditEntity.property( "string1" ) ) ).getSingleResult();
|
||||||
|
String expected = testEntity1.getString1().toUpperCase();
|
||||||
|
assertEquals( "Expected the property string1 to be upper case", expected, actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProjectionWithPropertyAndSimpleArguments() {
|
||||||
|
Object actual = getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||||
|
.addProjection( AuditEntity.function( "substring", AuditEntity.property( "string1" ), 3, 2 ) ).getSingleResult();
|
||||||
|
// the sql substring indices are 1 based while java substring indices are 0 based
|
||||||
|
// the sql substring second parameter denotes the length of the substring
|
||||||
|
// while in java the scond argument denotes the end index
|
||||||
|
String expected = testEntity1.getString1().substring( 2, 4 );
|
||||||
|
assertEquals( "Expected the substring of the property string1", expected, actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProjectionWithNestedFunction() {
|
||||||
|
Object actual = getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||||
|
.addProjection( AuditEntity.function( "concat",
|
||||||
|
AuditEntity.function( "upper", AuditEntity.property( "string1" ) ),
|
||||||
|
AuditEntity.function( "substring", AuditEntity.property( "string2" ), 1, 2 ) ) )
|
||||||
|
.getSingleResult();
|
||||||
|
final String expected = testEntity1.getString1().toUpperCase().concat( testEntity1.getString2().substring( 0, 2 ) );
|
||||||
|
assertEquals( "Expected the upper cased string1 to be concat with the first two characters of string2", expected, actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComparisonFunctionWithValue() {
|
||||||
|
TestEntity entity = (TestEntity) getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||||
|
.add( AuditEntity.function( "substring", AuditEntity.property( "string1" ), 3, 2 ).eq( "cd" ) ).getSingleResult();
|
||||||
|
assertNotNull( "Expected the entity to be returned", entity );
|
||||||
|
assertEquals( "Expected the entity to be returned", testEntity1.getId(), entity.getId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComparionFunctionWithProperty() {
|
||||||
|
TestEntity entity = (TestEntity) getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||||
|
.add( AuditEntity.function( "length", AuditEntity.property( "string2" ) ).ltProperty( "int1" ) ).getSingleResult();
|
||||||
|
assertNotNull( "Expected the entity to be returned", entity );
|
||||||
|
assertEquals( "Expected the entity to be returned", testEntity1.getId(), entity.getId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComparisonFunctionWithFunction() {
|
||||||
|
TestEntity entity = (TestEntity) getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||||
|
.add( AuditEntity.function( "substring", AuditEntity.property( "string2" ), 1, 2 )
|
||||||
|
.eqFunction( AuditEntity.function( "str", AuditEntity.property( "int1" ) ) ) )
|
||||||
|
.getSingleResult();
|
||||||
|
assertNotNull( "Expected the entity to be returned", entity );
|
||||||
|
assertEquals( "Expected the entity to be returned", testEntity1.getId(), entity.getId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComparisonPropertyWithFunction() {
|
||||||
|
TestEntity entity = (TestEntity) getAuditReader().createQuery().forEntitiesAtRevision( TestEntity.class, 1 )
|
||||||
|
.add( AuditEntity.property( "int1" ).gtFunction( AuditEntity.function( "length", AuditEntity.property( "string2" ) ) ) ).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