
com.querydsl.jpa.JPQLSerializer Maven / Gradle / Ivy
/*
* 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 com.querydsl.core.JoinExpression;
import com.querydsl.core.JoinType;
import com.querydsl.core.QueryMetadata;
import com.querydsl.core.support.SerializerBase;
import com.querydsl.core.types.CollectionExpression;
import com.querydsl.core.types.Constant;
import com.querydsl.core.types.ConstantImpl;
import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.FactoryExpression;
import com.querydsl.core.types.MapExpression;
import com.querydsl.core.types.Operation;
import com.querydsl.core.types.Operator;
import com.querydsl.core.types.Ops;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.PathType;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.SubQueryExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.util.MathUtils;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceUnitUtil;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.Metamodel;
import jakarta.persistence.metamodel.SingularAttribute;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
/**
* {@code JPQLSerializer} serializes Querydsl expressions into JPQL syntax.
*
* @author tiwe
*/
public class JPQLSerializer extends SerializerBase {
private static final Set extends Operator> NUMERIC =
Collections.unmodifiableSet(
EnumSet.of(
Ops.ADD, Ops.SUB, Ops.MULT, Ops.DIV, Ops.LT, Ops.LOE, Ops.GT, Ops.GOE, Ops.BETWEEN));
private static final Set extends Operator> CASE_OPS =
Collections.unmodifiableSet(EnumSet.of(Ops.CASE_ELSE));
private static final String COMMA = ", ";
private static final String DELETE = "delete from ";
private static final String FROM = "from ";
private static final String GROUP_BY = "\ngroup by ";
private static final String HAVING = "\nhaving ";
private static final String ORDER_BY = "\norder by ";
private static final String SELECT = "select ";
private static final String SELECT_COUNT = "select count(";
private static final String SELECT_COUNT_DISTINCT = "select count(distinct ";
private static final String SELECT_DISTINCT = "select distinct ";
private static final String SET = "\nset ";
private static final String UPDATE = "update ";
private static final String INSERT = "insert into ";
private static final String VALUES = "\nvalues ";
private static final String WHERE = "\nwhere ";
private static final String WITH = " with ";
private static final String ON = " on ";
private static final Map joinTypes =
new EnumMap(JoinType.class);
private final JPQLTemplates templates;
private final EntityManager entityManager;
private boolean inProjection = false;
private boolean inCaseOperation = false;
static {
joinTypes.put(JoinType.DEFAULT, COMMA);
joinTypes.put(JoinType.FULLJOIN, "\n full join ");
joinTypes.put(JoinType.INNERJOIN, "\n inner join ");
joinTypes.put(JoinType.JOIN, "\n inner join ");
joinTypes.put(JoinType.LEFTJOIN, "\n left join ");
joinTypes.put(JoinType.RIGHTJOIN, "\n right join ");
}
private boolean wrapElements = false;
public JPQLSerializer(JPQLTemplates templates) {
this(templates, null);
}
public JPQLSerializer(JPQLTemplates templates, EntityManager em) {
super(templates);
this.templates = templates;
this.entityManager = em;
}
private String getEntityName(Class> clazz) {
final Entity entityAnnotation = clazz.getAnnotation(Entity.class);
if (entityAnnotation != null && entityAnnotation.name().length() > 0) {
return entityAnnotation.name();
} else if (clazz.getPackage() != null && clazz.getPackage().getName().length() > 0) {
String pn = clazz.getPackage().getName();
return clazz.getName().substring(pn.length() + 1);
} else {
return clazz.getName();
}
}
private void handleJoinTarget(JoinExpression je) {
// type specifier
if (je.getTarget() instanceof EntityPath>) {
final EntityPath> pe = (EntityPath>) je.getTarget();
if (pe.getMetadata().isRoot()) {
append(getEntityName(pe.getType()));
append(" ");
}
handle(je.getTarget());
} else if (je.getTarget() instanceof Operation) {
Operation> op = (Operation) je.getTarget();
if (op.getOperator() == Ops.ALIAS) {
boolean treat = false;
if (Collection.class.isAssignableFrom(op.getArg(0).getType())) {
if (op.getArg(0) instanceof CollectionExpression) {
Class> par = ((CollectionExpression) op.getArg(0)).getParameter(0);
treat = !par.equals(op.getArg(1).getType());
}
} else if (Map.class.isAssignableFrom(op.getArg(0).getType())) {
if (op.getArg(0) instanceof MapExpression) {
Class> par = ((MapExpression) op.getArg(0)).getParameter(1);
treat = !par.equals(op.getArg(1).getType());
}
} else {
treat = !op.getArg(0).getType().equals(op.getArg(1).getType());
}
if (treat) {
Expression> entityName = ConstantImpl.create(getEntityName(op.getArg(1).getType()));
Expression> t =
ExpressionUtils.operation(op.getType(), JPQLOps.TREAT, op.getArg(0), entityName);
op = ExpressionUtils.operation(op.getType(), Ops.ALIAS, t, op.getArg(1));
}
}
handle(op);
} else {
handle(je.getTarget());
}
}
public void serialize(QueryMetadata metadata, boolean forCountRow, @Nullable String projection) {
final Expression> select = metadata.getProjection();
final List joins = metadata.getJoins();
final Predicate where = metadata.getWhere();
final List extends Expression>> groupBy = metadata.getGroupBy();
final Predicate having = metadata.getHaving();
final List> orderBy = metadata.getOrderBy();
// select
boolean inProjectionOrig = inProjection;
inProjection = true;
if (projection != null) {
append(SELECT).append(projection).append("\n");
} else if (forCountRow) {
if (!groupBy.isEmpty()) {
append(SELECT_COUNT_DISTINCT);
handle(", ", groupBy);
} else {
if (!metadata.isDistinct()) {
append(SELECT_COUNT);
} else {
append(SELECT_COUNT_DISTINCT);
}
if (select != null) {
if (select instanceof FactoryExpression) {
handle(joins.get(0).getTarget());
} else {
// TODO : make sure this works
handle(select);
}
} else {
handle(joins.get(0).getTarget());
}
}
append(")\n");
} else if (select != null || !joins.isEmpty()) {
if (!metadata.isDistinct()) {
append(SELECT);
} else {
append(SELECT_DISTINCT);
}
if (select != null) {
handle(select);
} else {
handle(joins.get(0).getTarget());
}
append("\n");
}
inProjection = inProjectionOrig;
// from
if (!joins.isEmpty()) {
append(FROM);
serializeSources(forCountRow, joins);
}
// where
if (where != null) {
append(WHERE).handle(where);
}
// group by
if (!groupBy.isEmpty() && !forCountRow) {
append(GROUP_BY).handle(COMMA, groupBy);
}
// having
if (having != null) {
append(HAVING).handle(having);
}
// order by
if (!orderBy.isEmpty() && !forCountRow) {
append(ORDER_BY);
boolean first = true;
for (final OrderSpecifier> os : orderBy) {
if (!first) {
append(COMMA);
}
handle(os.getTarget());
append(os.getOrder() == Order.ASC ? " asc" : " desc");
if (os.getNullHandling() == OrderSpecifier.NullHandling.NullsFirst) {
append(" nulls first");
} else if (os.getNullHandling() == OrderSpecifier.NullHandling.NullsLast) {
append(" nulls last");
}
first = false;
}
}
}
public void serializeForDelete(QueryMetadata md) {
append(DELETE);
handleJoinTarget(md.getJoins().get(0));
if (md.getWhere() != null) {
append(WHERE).handle(md.getWhere());
}
}
private static String relativePathString(Expression> root, Path> path) {
StringBuilder pathString = new StringBuilder(path.getMetadata().getName().length());
while (path.getMetadata().getParent() != null && !path.equals(root)) {
if (pathString.length() > 0) {
pathString.insert(0, '.');
}
pathString.insert(0, path.getMetadata().getName());
path = path.getMetadata().getParent();
}
return pathString.toString();
}
public void serializeForInsert(
QueryMetadata md,
Collection> columns,
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy