package org.quaere.dsl;
import org.quaere.IncompleteQueryException;
import org.quaere.QueryEngine;
import org.quaere.Queryable;
import org.quaere.QueryableIterable;
import org.quaere.expressions.*;
import java.util.*;
public class QueryExpressionBuilderImpl<R> implements
Iterable<R>,
QueryExpressionBuilder<R>,
FromClauseBuilder<R>,
DeclarationClauseBuilder<R>,
GroupClauseBuilder<R>,
QueryBodyBuilder<R>,
QueryContinuationBuider<R>,
QueryContinuationOrQueryBodyBuilder<R> {
private QueryExpressionBuilderImpl<R> parentQueryBuilder;
private Identifier currentIdentifier;
private Identifier currentGroupIdentifier;
private Identifier continuationIdentifier;
Map<Identifier, Queryable> sources = new HashMap<Identifier, Queryable>();
private FromClause fromClause;
List<QueryBodyClause> queryBodyClauses = new ArrayList<QueryBodyClause>();
private SelectOrGroupClause currentSelectOrGroupClause;
private QueryContinuation queryContinuation;
public Map<Identifier, Queryable> getSources() {
return sources;
}
private List<OrderByCriteria> currentOrderByCriterias = new ArrayList<OrderByCriteria>();
public QueryExpressionBuilderImpl() {
}
private QueryExpressionBuilderImpl(QueryExpressionBuilderImpl<R> parentQueryBuilder) {
this.parentQueryBuilder = parentQueryBuilder;
this.sources.putAll(parentQueryBuilder.sources);
}
private void addOrderByCriteria(Expression expression, OrderByCriteria.Direction direction, Comparator comparator) {
currentOrderByCriterias.add(new OrderByCriteria(expression, direction, comparator));
}
private void terminateOrderingClauses() {
if (currentOrderByCriterias.size() > 0) {
queryBodyClauses.add(new OrderByClause(currentOrderByCriterias));
currentOrderByCriterias = new ArrayList<OrderByCriteria>();
}
}
public QueryExpression getQueryExpression() {
if (parentQueryBuilder != null) {
QueryBody queryBody = new QueryBody(queryBodyClauses, currentSelectOrGroupClause, queryContinuation);
QueryExpression queryExpression = new QueryExpression(fromClause, queryBody);
return parentQueryBuilder.getQueryExpression(queryExpression.getQueryBody());
}
else {
if (currentSelectOrGroupClause == null) {
throw new IncompleteQueryException("A query must have a select or group by clause.");
}
QueryBody queryBody = new QueryBody(queryBodyClauses, currentSelectOrGroupClause, queryContinuation);
QueryExpression queryExpression = new QueryExpression(fromClause, queryBody);
return queryExpression;
}
}
private QueryExpression getQueryExpression(QueryBody continuationQueryBody) {
this.queryContinuation = new QueryContinuation(
continuationIdentifier,
continuationQueryBody
);
return getQueryExpression();
}
public Iterator<R> iterator() {
// if (parentQueryBuilder != null) {
// QueryExpression queryExpression = getQueryExpression();
// return parentQueryBuilder.iterator(queryExpression.getQueryBody());
// }
// else {
// if (currentSelectOrGroupClause == null) {
// throw new IncompleteQueryException("A query must have a select or group by clause.");
// }
QueryExpression queryExpression = getQueryExpression();
QueryEngine q = null;
for (Map.Entry<Identifier, Queryable> sourceEntry : sources.entrySet()) {
if (q == null) {
q = sourceEntry.getValue().createQueryEngine();
}
q.addSource(sourceEntry.getValue().getSourceIdentifier(sourceEntry.getKey()), sourceEntry.getValue());
}
if (q == null) {
throw new IncompleteQueryException("There are no sources to select from.");
}
Iterable<R> result = q.evaluate(queryExpression);
return result.iterator();
// }
}
public FromClauseBuilder<R> from(String identifier) {
currentIdentifier = new Identifier(identifier);
return this;
}
public FromClauseBuilder<R> from(QueryExpressionBuilder subquery) {
throw new RuntimeException("The method is not implemented");
}
public DeclarationClauseBuilder<R> declare(String identifier) {
currentIdentifier = new Identifier(identifier);
return this;
}
public QueryBodyBuilder<R> as(String expression) {
return as(LiteralExpression.parse(expression));
}
public QueryBodyBuilder<R> as(Expression expression) {
queryBodyClauses.add(new DeclareClause(currentIdentifier, expression));
currentIdentifier = null;
return this;
}
public QueryBodyBuilder<R> where(String predicate) {
return where(LiteralExpression.parse(predicate));
}
public QueryBodyBuilder<R> where(Expression predicate) {
queryBodyClauses.add(new WhereClause(predicate));
return this;
}
public JoinClauseBuilder<R> join(String identifer) {
return new JoinClauseBuilderImpl(this, new Identifier(identifer));
}
public QueryBodyBuilder<R> orderBy(String expression) {
return orderBy(expression, null);
}
public QueryBodyBuilder<R> orderBy(String expression, Comparator comparator) {
return orderBy(LiteralExpression.parse(expression), comparator);
}
public QueryBodyBuilder<R> orderBy(Expression expression) {
return orderBy(expression, null);
}
public QueryBodyBuilder<R> orderBy(Expression expression, Comparator comparator) {
addOrderByCriteria(expression, OrderByCriteria.Direction.ASCENDING, comparator);
return this;
}
public QueryBodyBuilder<R> orderByDescending(String expression) {
return orderByDescending(expression, null);
}
public QueryBodyBuilder<R> orderByDescending(String expression, Comparator comparator) {
return orderByDescending(LiteralExpression.parse(expression), comparator);
}
public QueryBodyBuilder<R> orderByDescending(Expression expression) {
return orderByDescending(expression, null);
}
public QueryBodyBuilder<R> orderByDescending(Expression expression, Comparator comparator) {
addOrderByCriteria(expression, OrderByCriteria.Direction.DESCENDING, comparator);
return this;
}
public <R> QueryContinuationOrQueryBodyBuilder<R> select(String expression) {
return select(LiteralExpression.parse(expression));
}
public <R> QueryContinuationOrQueryBodyBuilder<R> select(Expression expression) {
terminateOrderingClauses();
currentSelectOrGroupClause = new SelectClause(expression);
return (QueryContinuationOrQueryBodyBuilder<R>) this;
}
public GroupClauseBuilder<R> group(String identifier) {
terminateOrderingClauses();
currentGroupIdentifier = new Identifier(identifier);
return this;
}
public <T> QueryBodyBuilder<R> in(T[] source) {
return in(Arrays.asList(source));
}
public <T> QueryBodyBuilder<R> in(Iterable<T> source) {
return in(new QueryableIterable<T>(source));
}
public <T> QueryBodyBuilder<R> in(Queryable<T> source) {
sources.put(currentIdentifier, source);
return in(
new Statement(
Arrays.<Expression>asList(
new Identifier(source.getSourceIdentifier(currentIdentifier).name)
)
)
);
}
public QueryBodyBuilder<R> in(String expression) {
return in(LiteralExpression.parse(expression));
}
private QueryBodyBuilder<R> in(Expression expression) {
if (fromClause == null) {
// This is the intial from clause
fromClause = new FromClause(currentIdentifier, expression);
}
else {
queryBodyClauses.add(new FromClause(currentIdentifier, expression));
}
return this;
}
public QueryContinuationBuider<R> by(String expression) {
return by(LiteralExpression.parse(expression), null);
}
public QueryContinuationBuider<R> by(String expression, Comparator comparator) {
return by(LiteralExpression.parse(expression), comparator);
}
public QueryContinuationBuider<R> by(Expression expression) {
return by(expression, null);
}
public QueryContinuationBuider<R> by(Expression expression, Comparator comparator) {
currentSelectOrGroupClause = new GroupClause(
currentGroupIdentifier,
expression,
comparator
);
currentGroupIdentifier = null;
return this;
}
public QueryContinuationOrQueryBodyBuilder<R> into(String identifier) {
if (currentSelectOrGroupClause instanceof GroupClause) {
// Are we creating a source from a group by?
this.continuationIdentifier = new Identifier(identifier);
return new QueryExpressionBuilderImpl<R>(this);
}
else {
// ..or was is a join?
JoinClause nonGroupedJoin = (JoinClause) queryBodyClauses.get(queryBodyClauses.size() - 1);
JoinClause groupedJoin = new JoinClause(
nonGroupedJoin.identifier,
nonGroupedJoin.inIndentifier,
nonGroupedJoin.onExpression,
nonGroupedJoin.keyEqualityExpression,
new Identifier(identifier)
);
queryBodyClauses.remove(nonGroupedJoin);
queryBodyClauses.add(groupedJoin);
return this;
}
}
}