package org.raidenjpa.query.executor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.raidenjpa.db.InMemoryDB;
import org.raidenjpa.query.parser.FromClause;
import org.raidenjpa.query.parser.FromClauseItem;
import org.raidenjpa.query.parser.GroupByElements;
import org.raidenjpa.query.parser.JoinClause;
import org.raidenjpa.query.parser.QueryParser;
import org.raidenjpa.query.parser.WithClause;
import org.raidenjpa.util.BadSmell;
import org.raidenjpa.util.FixMe;
public class QueryExecutor {
private Integer maxResult;
private int firstResult;
private Map<String, Object> parameters;
private QueryParser queryParser;
public QueryExecutor(String jpql, Map<String, Object> parameters, Integer maxResult) {
this.queryParser = new QueryParser(jpql);
this.parameters = parameters;
this.maxResult = maxResult;
this.firstResult = 0;
}
public QueryExecutor(QueryParser queryParser, Map<String, Object> parameters) {
this.queryParser = queryParser;
this.parameters = parameters;
}
@FixMe("Which one is the first, group or order?")
public List<?> getResultList() {
showJpql();
QueryResult queryResult = new QueryResult();
executeFrom(queryResult);
executeJoin(queryResult);
executeWhere(queryResult);
executeGroup(queryResult);
executeOrderBy(queryResult);
executeLimit(queryResult);
return queryResult.getList(queryParser.getSelect(), queryParser.getGroupBy());
}
private void executeGroup(QueryResult queryResult) {
if (queryParser.getGroupBy() == null && !queryParser.getSelect().isThereAggregationFunction()) {
return;
}
List<List<String>> paths = new ArrayList<List<String>>();
if (queryParser.getGroupBy() == null) {
paths.add(Arrays.asList("fake_aggregation_for_group_all_rows"));
} else {
for (GroupByElements groupByElements : queryParser.getGroupBy().getElements()) {
paths.add(groupByElements.getPath());
}
}
queryResult.group(paths);
}
private void showJpql() {
String jpql = queryParser.getWords().getJpql();
for (Entry<String, Object> entry : parameters.entrySet()) {
jpql = jpql.replaceAll(":" + entry.getKey(), entry.getValue().toString());
}
}
private void executeOrderBy(QueryResult queryResult) {
queryResult.sort(queryParser.getOrderBy());
}
@BadSmell("It is kind of confused. Put it in QueryResult")
private void executeJoin(QueryResult queryResult) {
if (queryResult.size() == 0) {
return;
}
for (JoinClause join : queryParser.getJoins()) {
queryResult.join(join, queryParser.getWhere(), parameters);
}
// @FixMe - There is some case when IN is not equals to JOIN, study it
for (FromClauseItem item : queryParser.getFrom().getItens()) {
if (item.isInFrom()) {
JoinClause join = new JoinClause();
join.setAlias(item.getAliasName());
join.setPath(item.getInPath());
join.setWith(new WithClause());
queryResult.join(join, queryParser.getWhere(), parameters);
}
}
}
@FixMe("Execute limit before than group by is correct?")
private void executeLimit(QueryResult queryResult) {
queryResult.limit(firstResult, maxResult);
}
private void executeWhere(QueryResult queryResult) {
if (!queryParser.getWhere().hasElements()) {
return;
}
LogicExpressionExecutor logicExpressionExecutor = new LogicExpressionExecutor(queryParser.getWhere().getLogicExpression(), parameters);
Iterator<QueryResultRow> it = queryResult.iterator();
while(it.hasNext()) {
QueryResultRow row = it.next();
if (!logicExpressionExecutor.match(row, true)) {
it.remove();
}
}
}
@BadSmell("Refactory")
private void executeFrom(QueryResult queryResult) {
FromClause from = queryParser.getFrom();
for (FromClauseItem item : from.getItens()) {
if (!item.isInFrom()) {
List<Object> rowsInDB = InMemoryDB.me().getAll(item.getClassName());
queryResult.addFrom(item.getAliasName(), rowsInDB);
}
}
}
public QueryExecutor setFirstResult(int first) {
this.firstResult = first;
return this;
}
}