package org.sothis.dal.solr;
import java.util.List;
import java.util.Map;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.sothis.dal.AbstractJpaCompatibleDao.PropertyInfo;
import org.sothis.dal.query.Chain;
import org.sothis.dal.query.Cnd;
import org.sothis.dal.query.Logic;
import org.sothis.dal.query.Op;
import org.sothis.dal.query.Sort;
public class SolrQueryBuilder {
private final Map<String, PropertyInfo> propertyMap;
public SolrQueryBuilder(Map<String, PropertyInfo> propertyMap) {
this.propertyMap = propertyMap;
}
private String mapField(String property) {
PropertyInfo pi = propertyMap.get(property);
if (null == pi) {
throw new IllegalArgumentException("no property named [" + property + "] found.");
}
return pi.getColumn().name();
}
public SolrQuery buildQuery(Cnd cnd, Chain chain) {
SolrQuery query = new SolrQuery();
Query q = buildLuceneQuery(cnd);
String queryString = null == q ? "*:*" : q.toString();
query.setQuery(queryString);
if (null != chain) {
for (Chain c : chain) {
query.addField(mapField(c.name()));
}
}
List<Sort> sorts = cnd.getSorts();
if (!sorts.isEmpty()) {
for (Sort sort : sorts) {
query.addSortField(mapField(sort.getField()), sort.isAsc() ? ORDER.asc : ORDER.desc);
}
}
return query;
}
@SuppressWarnings("unchecked")
private Query buildLuceneQuery(Cnd cnd) {
if (null == cnd) {
return null;
}
Object op = cnd.getOp();
if (op instanceof Op) {
LuceneQueryBuilder luceneQB = new LuceneQueryBuilder();
BooleanClause.Occur occur = cnd.isNot() ? BooleanClause.Occur.MUST_NOT : BooleanClause.Occur.MUST;
switch ((Op) op) {
case EQ:
luceneQB.eq(mapField((String) cnd.getLeft()), cnd.getRight(), occur);
break;
case GT:
luceneQB.gt(mapField((String) cnd.getLeft()), cnd.getRight(), occur);
break;
case GTE:
luceneQB.gte(mapField((String) cnd.getLeft()), cnd.getRight(), occur);
break;
case IN:
luceneQB.in(mapField((String) cnd.getLeft()), (List<Object>) cnd.getRight(), occur);
break;
case LIKE:
break;
case LT:
luceneQB.lt(mapField((String) cnd.getLeft()), cnd.getRight(), occur);
break;
case LTE:
luceneQB.lte(mapField((String) cnd.getLeft()), cnd.getRight(), occur);
break;
case NE:
luceneQB.ne(mapField((String) cnd.getLeft()), cnd.getRight(), occur);
break;
case NIN:
default:
throw new RuntimeException("unsupported op: " + op);
}
return luceneQB.toQuery();
} else if (op instanceof Logic) {
BooleanQuery query = new BooleanQuery();
switch ((Logic) op) {
case AND:
query.add(buildLuceneQuery((Cnd) cnd.getLeft()), BooleanClause.Occur.MUST);
query.add(buildLuceneQuery((Cnd) cnd.getRight()), BooleanClause.Occur.MUST);
break;
case OR:
query.add(buildLuceneQuery((Cnd) cnd.getLeft()), BooleanClause.Occur.SHOULD);
query.add(buildLuceneQuery((Cnd) cnd.getRight()), BooleanClause.Occur.SHOULD);
break;
}
if (cnd.isNot()) {
BooleanQuery q = new BooleanQuery();
q.add(query, BooleanClause.Occur.MUST_NOT);
return q;
} else {
return query;
}
} else {
throw new RuntimeException("unknown op: " + op);
}
}
}