/*
* Copyright 2015, The Querydsl Team (http://www.querydsl.com/team)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.querydsl.core.support;
import com.querydsl.core.types.*;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.SimplePath;
/**
* {@code CollectionAnyVisitor} is an expression visitor which transforms any() path expressions which are
* often transformed into subqueries
*
* @author tiwe
*
*/
@SuppressWarnings("unchecked")
public class CollectionAnyVisitor implements Visitor<Expression<?>,Context> {
private int replacedCounter;
@SuppressWarnings("rawtypes")
private static <T> Path<T> replaceParent(Path<T> path, Path<?> parent) {
PathMetadata metadata = new PathMetadata(parent, path.getMetadata().getElement(),
path.getMetadata().getPathType());
if (path instanceof CollectionExpression) {
CollectionExpression<?,?> col = (CollectionExpression<?,?>) path;
return (Path<T>) Expressions.listPath(col.getParameter(0), SimplePath.class, metadata);
} else {
return ExpressionUtils.path(path.getType(), metadata);
}
}
@Override
public Expression<?> visit(Constant<?> expr, Context context) {
return expr;
}
@Override
public Expression<?> visit(TemplateExpression<?> expr, Context context) {
Object[] args = new Object[expr.getArgs().size()];
for (int i = 0; i < args.length; i++) {
Context c = new Context();
if (expr.getArg(i) instanceof Expression) {
args[i] = ((Expression<?>) expr.getArg(i)).accept(this, c);
} else {
args[i] = expr.getArg(i);
}
context.add(c);
}
if (context.replace) {
if (expr.getType().equals(Boolean.class)) {
Predicate predicate = Expressions.booleanTemplate(expr.getTemplate(), args);
return !context.paths.isEmpty() ? exists(context, predicate) : predicate;
} else {
return ExpressionUtils.template(expr.getType(), expr.getTemplate(), args);
}
} else {
return expr;
}
}
@Override
public Expression<?> visit(FactoryExpression<?> expr, Context context) {
return expr;
}
@SuppressWarnings("rawtypes")
@Override
public Expression<?> visit(Operation<?> expr, Context context) {
Expression<?>[] args = new Expression<?>[expr.getArgs().size()];
for (int i = 0; i < args.length; i++) {
Context c = new Context();
args[i] = expr.getArg(i).accept(this, c);
context.add(c);
}
if (context.replace) {
if (expr.getType().equals(Boolean.class)) {
Predicate predicate = ExpressionUtils.predicate(expr.getOperator(), args);
return !context.paths.isEmpty() ? exists(context, predicate) : predicate;
} else {
return ExpressionUtils.operation(expr.getType(), expr.getOperator(), args);
}
} else {
return expr;
}
}
protected Predicate exists(Context c, Predicate condition) {
return condition;
}
@Override
public Expression<?> visit(Path<?> expr, Context context) {
if (expr.getMetadata().getPathType() == PathType.COLLECTION_ANY) {
Path<?> parent = (Path<?>) expr.getMetadata().getParent().accept(this, context);
expr = ExpressionUtils.path(expr.getType(), PathMetadataFactory.forCollectionAny(parent));
EntityPath<?> replacement = new EntityPathBase<Object>(expr.getType(),
ExpressionUtils.createRootVariable(expr, replacedCounter++));
context.add(expr, replacement);
return replacement;
} else if (expr.getMetadata().getParent() != null) {
Context c = new Context();
Path<?> parent = (Path<?>) expr.getMetadata().getParent().accept(this, c);
if (c.replace) {
context.add(c);
return replaceParent(expr, parent);
}
}
return expr;
}
@Override
public Expression<?> visit(SubQueryExpression<?> expr, Context context) {
return expr;
}
@Override
public Expression<?> visit(ParamExpression<?> expr, Context context) {
return expr;
}
}