mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-13 21:01:01 +08:00
246 lines
8.1 KiB
Java
246 lines
8.1 KiB
Java
/*
|
|
* Copyright (c) 2009 Mysema Ltd.
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
package com.mysema.query.sql;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
import com.mysema.query.JoinExpression;
|
|
import com.mysema.query.QueryMetadata;
|
|
import com.mysema.query.serialization.BaseSerializer;
|
|
import com.mysema.query.types.Order;
|
|
import com.mysema.query.types.OrderSpecifier;
|
|
import com.mysema.query.types.expr.EBoolean;
|
|
import com.mysema.query.types.expr.EConstant;
|
|
import com.mysema.query.types.expr.EConstructor;
|
|
import com.mysema.query.types.expr.Expr;
|
|
import com.mysema.query.types.operation.Operator;
|
|
import com.mysema.query.types.operation.Ops;
|
|
import com.mysema.query.types.path.PEntity;
|
|
import com.mysema.query.types.query.ListSubQuery;
|
|
import com.mysema.query.types.query.ObjectSubQuery;
|
|
import com.mysema.query.types.query.SubQuery;
|
|
|
|
/**
|
|
* SqlSerializer serializes Querydsl queries into SQL
|
|
*
|
|
* @author tiwe
|
|
* @version $Id$
|
|
*/
|
|
public class SQLSerializer extends BaseSerializer<SQLSerializer> {
|
|
|
|
private final List<Object> constants = new ArrayList<Object>();
|
|
|
|
protected final SQLPatterns patterns;
|
|
|
|
public SQLSerializer(SQLPatterns patterns) {
|
|
super(patterns);
|
|
this.patterns = patterns;
|
|
}
|
|
|
|
protected void beforeOrderBy() {
|
|
// template method, for subclasses do override
|
|
}
|
|
|
|
public List<Object> getConstants(){
|
|
return constants;
|
|
}
|
|
|
|
public void serialize(QueryMetadata metadata, boolean forCountRow) {
|
|
List<? extends Expr<?>> select = metadata.getProjection();
|
|
List<JoinExpression> joins = metadata.getJoins();
|
|
EBoolean where = metadata.getWhere();
|
|
List<? extends Expr<?>> groupBy = metadata.getGroupBy();
|
|
EBoolean having = metadata.getHaving();
|
|
List<OrderSpecifier<?>> orderBy = metadata.getOrderBy();
|
|
|
|
if (forCountRow) {
|
|
append(patterns.select()).append(patterns.countStar());
|
|
} else if (!select.isEmpty()) {
|
|
if (!metadata.isDistinct()) {
|
|
append(patterns.select());
|
|
} else {
|
|
append(patterns.selectDistinct());
|
|
}
|
|
List<Expr<?>> sqlSelect = new ArrayList<Expr<?>>();
|
|
for (Expr<?> selectExpr : select) {
|
|
if (selectExpr instanceof EConstructor) {
|
|
// transforms constructor arguments into individual select
|
|
// expressions
|
|
sqlSelect.addAll(((EConstructor<?>) selectExpr).getArgs());
|
|
} else {
|
|
sqlSelect.add(selectExpr);
|
|
}
|
|
}
|
|
handle(", ", sqlSelect);
|
|
}
|
|
append(patterns.from());
|
|
if (joins.isEmpty()) {
|
|
// TODO : disallow usage of dummy table ?!?
|
|
append(patterns.dummyTable());
|
|
|
|
}
|
|
for (int i = 0; i < joins.size(); i++) {
|
|
JoinExpression je = joins.get(i);
|
|
if (i > 0) {
|
|
String sep = ", ";
|
|
switch (je.getType()) {
|
|
case FULLJOIN:
|
|
sep = patterns.fullJoin();
|
|
break;
|
|
case INNERJOIN:
|
|
sep = patterns.innerJoin();
|
|
break;
|
|
case JOIN:
|
|
sep = patterns.join();
|
|
break;
|
|
case LEFTJOIN:
|
|
sep = patterns.leftJoin();
|
|
break;
|
|
}
|
|
append(sep);
|
|
}
|
|
|
|
// type specifier
|
|
if (je.getTarget() instanceof PEntity && patterns.supportsAlias()) {
|
|
PEntity<?> pe = (PEntity<?>) je.getTarget();
|
|
if (pe.getMetadata().getParent() == null) {
|
|
append(pe.getEntityName()).append(patterns.tableAlias());
|
|
}
|
|
}
|
|
handle(je.getTarget());
|
|
if (je.getCondition() != null) {
|
|
append(patterns.on()).handle(je.getCondition());
|
|
}
|
|
}
|
|
|
|
if (where != null) {
|
|
append(patterns.where()).handle(where);
|
|
}
|
|
if (!groupBy.isEmpty()) {
|
|
append(patterns.groupBy()).handle(", ", groupBy);
|
|
}
|
|
if (having != null) {
|
|
if (groupBy.isEmpty()) {
|
|
throw new IllegalArgumentException(
|
|
"having, but not groupBy was given");
|
|
}
|
|
append(patterns.having()).handle(having);
|
|
}
|
|
|
|
beforeOrderBy();
|
|
|
|
Long limit = metadata.getModifiers().getLimit();
|
|
Long offset = metadata.getModifiers().getOffset();
|
|
|
|
if (!patterns.limitAndOffsetSymbols()
|
|
&& metadata.getModifiers().isRestricting() && !forCountRow) {
|
|
if (where == null){
|
|
append(patterns.where());
|
|
}
|
|
append(patterns.limitOffsetCondition(limit, offset));
|
|
}
|
|
|
|
if (!orderBy.isEmpty() && !forCountRow) {
|
|
append(patterns.orderBy());
|
|
boolean first = true;
|
|
for (OrderSpecifier<?> os : orderBy) {
|
|
if (!first){
|
|
builder.append(", ");
|
|
}
|
|
handle(os.getTarget());
|
|
append(os.getOrder() == Order.ASC ? patterns.asc() : patterns.desc());
|
|
first = false;
|
|
}
|
|
}
|
|
if (patterns.limitAndOffsetSymbols()
|
|
&& metadata.getModifiers().isRestricting() && !forCountRow) {
|
|
if (limit != null) {
|
|
append(patterns.limit()).append(String.valueOf(limit));
|
|
}
|
|
if (offset != null) {
|
|
append(patterns.offset()).append(String.valueOf(offset));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void serializeUnion(SubQuery[] sqs,
|
|
List<OrderSpecifier<?>> orderBy) {
|
|
// union
|
|
handle(patterns.union(), (List)Arrays.asList(sqs));
|
|
|
|
// order by
|
|
if (!orderBy.isEmpty()) {
|
|
append(patterns.orderBy());
|
|
boolean first = true;
|
|
for (OrderSpecifier<?> os : orderBy) {
|
|
if (!first)
|
|
builder.append(", ");
|
|
handle(os.getTarget());
|
|
append(os.getOrder() == Order.ASC ? patterns.asc() : patterns.desc());
|
|
first = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void visit(EConstant<?> expr) {
|
|
append("?");
|
|
constants.add(expr.getConstant());
|
|
}
|
|
|
|
private void visitCast(Operator<?> operator, Expr<?> source, Class<?> targetType) {
|
|
// TODO : move constants to SqlOps
|
|
append("cast(").handle(source);
|
|
append(" as ");
|
|
append(patterns.getClass2Type().get(targetType)).append(")");
|
|
|
|
}
|
|
|
|
@Override
|
|
protected void visitOperation(Class<?> type, Operator<?> operator,
|
|
List<Expr<?>> args) {
|
|
if (operator.equals(Ops.STRING_CAST)) {
|
|
visitCast(operator, args.get(0), String.class);
|
|
} else if (operator.equals(Ops.NUMCAST)) {
|
|
visitCast(operator, args.get(0), (Class<?>) ((EConstant<?>) args
|
|
.get(1)).getConstant());
|
|
} else {
|
|
super.visitOperation(type, operator, args);
|
|
}
|
|
}
|
|
|
|
protected void visit(ObjectSubQuery<?> query) {
|
|
visit((SubQuery)query);
|
|
}
|
|
|
|
protected void visit(ListSubQuery<?> query) {
|
|
visit((SubQuery)query);
|
|
}
|
|
|
|
protected void visit(SubQuery query) {
|
|
append("(");
|
|
serialize(query.getMetadata(), false);
|
|
append(")");
|
|
}
|
|
|
|
protected void visit(SumOver<?> expr) {
|
|
append(patterns.sum()).append("(").handle(expr.getTarget()).append(") ");
|
|
append(patterns.over());
|
|
append(" (");
|
|
if (expr.getPartitionBy() != null) {
|
|
append(patterns.partitionBy()).handle(expr.getPartitionBy());
|
|
}
|
|
if (!expr.getOrderBy().isEmpty()) {
|
|
append(patterns.orderBy()).handle(", ", expr.getOrderBy());
|
|
}
|
|
append(")");
|
|
}
|
|
|
|
}
|