querydsl/querydsl-sql/src/main/java/com/mysema/query/sql/SQLSerializer.java
2009-08-11 12:55:39 +00:00

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(")");
}
}