package org.hibernate.query.criteria.internal;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.metamodel.SingularAttribute;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
import org.hibernate.query.criteria.internal.path.SingularAttributePath;
public class CriteriaUpdateImpl<T> extends AbstractManipulationCriteriaQuery<T> implements CriteriaUpdate<T> {
private List<Assignment> assignments = new ArrayList<Assignment>();
public CriteriaUpdateImpl(CriteriaBuilderImpl criteriaBuilder) {
super( criteriaBuilder );
}
@Override
@SuppressWarnings("unchecked")
public <Y, X extends Y> CriteriaUpdate<T> set(SingularAttribute<? super T, Y> singularAttribute, X value) {
final Path<Y> attributePath = getRoot().get( singularAttribute );
final Expression valueExpression = value == null
? criteriaBuilder().nullLiteral( attributePath.getJavaType() )
: criteriaBuilder().literal( value );
addAssignment( attributePath, valueExpression );
return this;
}
@Override
public <Y> CriteriaUpdate<T> set(
SingularAttribute<? super T, Y> singularAttribute,
Expression<? extends Y> value) {
addAssignment( getRoot().get( singularAttribute ), value );
return this;
}
@Override
@SuppressWarnings("unchecked")
public <Y, X extends Y> CriteriaUpdate<T> set(Path<Y> attributePath, X value) {
final Expression valueExpression = value == null
? criteriaBuilder().nullLiteral( attributePath.getJavaType() )
: criteriaBuilder().literal( value );
addAssignment( attributePath, valueExpression );
return this;
}
@Override
public <Y> CriteriaUpdate<T> set(Path<Y> attributePath, Expression<? extends Y> value) {
addAssignment( attributePath, value );
return this;
}
@Override
@SuppressWarnings("unchecked")
public CriteriaUpdate<T> set(String attributeName, Object value) {
final Path attributePath = getRoot().get( attributeName );
final Expression valueExpression = value == null
? criteriaBuilder().nullLiteral( attributePath.getJavaType() )
: criteriaBuilder().literal( value );
addAssignment( attributePath, valueExpression );
return this;
}
protected <Y> void addAssignment(Path<Y> attributePath, Expression<? extends Y> value) {
if ( ! PathImplementor.class.isInstance( attributePath ) ) {
throw new IllegalArgumentException( "Unexpected path implementation type : " + attributePath.getClass().getName() );
}
if ( ! SingularAttributePath.class.isInstance( attributePath ) ) {
throw new IllegalArgumentException(
"Attribute path for assignment must represent a singular attribute ["
+ ( (PathImplementor) attributePath ).getPathIdentifier() + "]"
);
}
if ( value == null ) {
throw new IllegalArgumentException( "Assignment value expression cannot be null. Did you mean to pass null as a literal?" );
}
assignments.add( new Assignment<Y>( (SingularAttributePath<Y>) attributePath, value ) );
}
@Override
public CriteriaUpdate<T> where(Expression<Boolean> restriction) {
setRestriction( restriction );
return this;
}
@Override
public CriteriaUpdate<T> where(Predicate... restrictions) {
setRestriction( restrictions );
return this;
}
@Override
public void validate() {
super.validate();
if ( assignments.isEmpty() ) {
throw new IllegalStateException( "No assignments specified as part of UPDATE criteria" );
}
}
@Override
protected String renderQuery(RenderingContext renderingContext) {
final StringBuilder jpaql = new StringBuilder( "update " );
renderRoot( jpaql, renderingContext );
renderAssignments( jpaql, renderingContext );
renderRestrictions( jpaql, renderingContext );
return jpaql.toString();
}
private void renderAssignments(StringBuilder jpaql, RenderingContext renderingContext) {
jpaql.append( " set " );
boolean first = true;
for ( Assignment assignment : assignments ) {
if ( ! first ) {
jpaql.append( ", " );
}
jpaql.append( assignment.attributePath.render( renderingContext ) )
.append( " = " )
.append( assignment.value.render( renderingContext ) );
first = false;
}
}
private static class Assignment<A> {
private final SingularAttributePath<A> attributePath;
private final ExpressionImplementor<? extends A> value;
private Assignment(SingularAttributePath<A> attributePath, Expression<? extends A> value) {
this.attributePath = attributePath;
this.value = (ExpressionImplementor) value;
}
}
}