/* * 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.jpa; import java.util.List; import javax.persistence.Entity; import com.google.common.collect.Lists; import com.querydsl.core.support.ConstantHidingExpression; import com.querydsl.core.support.EnumConversion; import com.querydsl.core.support.NumberConversion; import com.querydsl.core.support.NumberConversions; import com.querydsl.core.types.*; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.sql.RelationalPath; import com.querydsl.sql.SQLOps; /** * {@code Conversions} provides module specific projection conversion functionality * * @author tiwe * */ public final class Conversions { public static <RT> Expression<RT> convert(Expression<RT> expr) { if (expr instanceof FactoryExpression) { FactoryExpression<RT> factoryExpr = (FactoryExpression<RT>) expr; for (Expression<?> e: factoryExpr.getArgs()) { if (needsConstantRemoval(e)) { return convert(new ConstantHidingExpression<RT>(factoryExpr)); } } for (Expression<?> e : factoryExpr.getArgs()) { if (needsNumberConversion(e)) { return new NumberConversions<RT>(factoryExpr); } } } else if (needsNumberConversion(expr)) { return new NumberConversion<RT>(expr); } return expr; } private static boolean needsConstantRemoval(Expression<?> expr) { expr = ExpressionUtils.extract(expr); return expr instanceof Constant || expr.equals(Expressions.TRUE) || expr.equals(Expressions.FALSE) || (expr instanceof Operation && ((Operation<?>) expr).getOperator() == Ops.ALIAS && needsConstantRemoval(((Operation<?>) expr).getArg(0))); } private static boolean needsNumberConversion(Expression<?> expr) { expr = ExpressionUtils.extract(expr); return Number.class.isAssignableFrom(expr.getType()) && !Path.class.isInstance(expr); } private static boolean isEntityPathAndNeedsWrapping(Expression<?> expr) { if ((expr instanceof Path && expr.getType().isAnnotationPresent(Entity.class)) || (expr instanceof EntityPath && !RelationalPath.class.isInstance(expr))) { Path<?> path = (Path<?>) expr; if (path.getMetadata().getParent() == null) { return true; } } return false; } private static <RT> FactoryExpression<RT> createEntityPathConversions(FactoryExpression<RT> factoryExpr) { List<Expression<?>> conversions = Lists.newArrayList(); for (Expression<?> e : factoryExpr.getArgs()) { if (isEntityPathAndNeedsWrapping(e)) { conversions.add(ExpressionUtils.operation(e.getType(), SQLOps.ALL, e)); } else { conversions.add(e); } } return FactoryExpressionUtils.wrap(factoryExpr, conversions); } public static <RT> Expression<RT> convertForNativeQuery(Expression<RT> expr) { if (isEntityPathAndNeedsWrapping(expr)) { return ExpressionUtils.operation(expr.getType(), SQLOps.ALL, expr); } else if (Number.class.isAssignableFrom(expr.getType())) { return new NumberConversion<RT>(expr); } else if (Enum.class.isAssignableFrom(expr.getType())) { return new EnumConversion<RT>(expr); } else if (expr instanceof FactoryExpression) { FactoryExpression<RT> factoryExpr = (FactoryExpression<RT>) expr; boolean numberConversions = false; boolean hasEntityPath = false; for (Expression<?> e : factoryExpr.getArgs()) { if (isEntityPathAndNeedsWrapping(e)) { hasEntityPath = true; } else if (Number.class.isAssignableFrom(e.getType())) { numberConversions = true; } else if (Enum.class.isAssignableFrom(e.getType())) { numberConversions = true; } } if (hasEntityPath) { factoryExpr = createEntityPathConversions(factoryExpr); } if (numberConversions) { factoryExpr = new NumberConversions<RT>(factoryExpr); } return factoryExpr; } return expr; } private Conversions() { } }