/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2008.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.sail.rdbms.evaluation;
import java.util.ArrayList;
import java.util.List;
/**
* Facilitates the building of a JOIN or FROM clause in SQL.
*
* @author James Leigh
*
*/
public class SqlJoinBuilder {
private boolean left;
private SqlQueryBuilder subquery;
private String table;
private String alias;
private QueryBuilderFactory factory;
private List<SqlJoinBuilder> joins = new ArrayList<SqlJoinBuilder>();
private SqlExprBuilder on;
private List<SqlJoinBuilder> leftJoins = new ArrayList<SqlJoinBuilder>();
public SqlJoinBuilder(String table, String alias,
QueryBuilderFactory factory) {
super();
this.table = table;
this.alias = alias;
this.factory = factory;
on = factory.createSqlExprBuilder();
}
public boolean isLeft() {
return left;
}
public void setLeft(boolean left) {
this.left = left;
}
public String getTable() {
if (subquery == null)
return table;
return "( " + subquery.toString() + " )";
}
public String getAlias() {
return alias;
}
public List<SqlJoinBuilder> getLeftJoins() {
return leftJoins;
}
public SqlJoinBuilder on(String column, String expression) {
on.and().column(alias, column).eq().append(expression);
return this;
}
public SqlJoinBuilder findJoin(String alias) {
if (alias.equals(this.alias))
return this;
SqlJoinBuilder result;
for (SqlJoinBuilder join : joins) {
result = join.findJoin(alias);
if (result != null)
return result;
}
for (SqlJoinBuilder join : leftJoins) {
result = join.findJoin(alias);
if (result != null)
return result;
}
return null;
}
public SqlJoinBuilder join(String table, String alias) {
SqlJoinBuilder join = findJoin(alias);
if (join != null)
return join;
join = factory.createSqlJoinBuilder(table, alias);
joins.add(join);
return join;
}
public SqlJoinBuilder leftjoin(String table, String alias) {
SqlJoinBuilder join = findJoin(alias);
if (join != null)
return join;
join = factory.createSqlJoinBuilder(table, alias);
join.setLeft(true);
leftJoins.add(join);
return join;
}
public SqlJoinBuilder join(String alias) {
SqlJoinBuilder join = findJoin(alias);
if (join != null)
return join;
join = factory.createSqlJoinBuilder(null, alias);
joins.add(join);
return join;
}
public SqlJoinBuilder leftjoin(String alias) {
SqlJoinBuilder join = findJoin(alias);
if (join != null)
return join;
join = factory.createSqlJoinBuilder(null, alias);
join.setLeft(true);
leftJoins.add(join);
return join;
}
public SqlQueryBuilder subquery() {
assert table == null : table;
assert subquery == null : subquery;
return subquery = factory.createSqlQueryBuilder();
}
public SqlExprBuilder on() {
return on;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (isLeft()) {
sb.append("LEFT ");
}
sb.append("JOIN ").append(getJoinClause());
sb.append(" ON (").append(on()).append(")");
return sb.toString();
}
public CharSequence getFromClause() {
if (joins.isEmpty() && leftJoins.isEmpty())
return getTable() + " " + alias;
StringBuilder from = new StringBuilder();
from.append(getTable()).append(" ").append(alias);
for (SqlJoinBuilder join : joins) {
appendJoin(from, join);
}
for (SqlJoinBuilder left : getLeftJoins()) {
from.append("\n LEFT JOIN ").append(left.getJoinClause());
from.append(" ON (").append(left.on()).append(")");
}
return from;
}
protected CharSequence getJoinClause() {
if (joins.isEmpty() && leftJoins.isEmpty())
return getTable() + " " + alias;
StringBuilder from = new StringBuilder();
from.append("(");
from.append(getFromClause());
from.append(")");
return from;
}
protected void appendJoin(StringBuilder from, SqlJoinBuilder join) {
if (join.isLeft()) {
from.append("\n LEFT JOIN ").append(join.getJoinClause());
} else if (join.on().isEmpty()) {
from.append(getSqlCrossJoin()).append(join.getJoinClause());
} else {
from.append("\n INNER JOIN ").append(join.getJoinClause());
}
if (!join.on().isEmpty()) {
from.append(" ON (").append(join.on()).append(")");
} else if (join.isLeft()) {
from.append(" ON (").append(alias).append(".ctx = ").append(alias)
.append(".ctx)");
}
}
protected String getSqlCrossJoin() {
return "\n CROSS JOIN ";
}
public List<Object> findParameters(List<Object> parameters) {
if (subquery != null) {
subquery.findParameters(parameters);
}
for (SqlJoinBuilder join : joins) {
join.findParameters(parameters);
}
for (SqlJoinBuilder join : leftJoins) {
join.findParameters(parameters);
}
parameters.addAll(on.getParameters());
return parameters;
}
}