package org.molgenis.data.rsql;
import cz.jirutka.rsql.parser.ast.*;
import org.apache.commons.lang3.StringUtils;
import org.molgenis.data.*;
import org.molgenis.data.aggregation.AggregateQuery;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.data.support.AggregateQueryImpl;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* RSQLVisitor implementation for molgenis Query.
*
* @see <a href="https://github.com/jirutka/rsql-parser">https://github.com/jirutka/rsql-parser</a>
*/
public class AggregateQueryRsqlVisitor extends NoArgRSQLVisitorAdapter<AggregateQuery>
{
private final EntityType entityType;
private final AggregateQueryImpl aggsQ;
public AggregateQueryRsqlVisitor(EntityType entityType, Query<Entity> query)
{
this.entityType = checkNotNull(entityType);
this.aggsQ = new AggregateQueryImpl().query(query);
}
@Override
public AggregateQuery visit(AndNode node)
{
for (Node child : node)
{
child.accept(this);
}
return aggsQ;
}
@Override
public AggregateQuery visit(OrNode node)
{
throw new MolgenisQueryException("RSQL query operator OR (';' or 'or') not allowed in aggregates query");
}
@Override
public AggregateQuery visit(ComparisonNode node)
{
String symbol = node.getOperator().getSymbol();
if (!symbol.equals("=="))
{
throw new MolgenisQueryException(
String.format("RSQL query symbol [%s] not allowed in aggregates query, use ['==']", symbol));
}
String selector = node.getSelector();
switch (selector)
{
case "x":
aggsQ.setAttributeX(getAttribute(node));
break;
case "y":
aggsQ.setAttributeY(getAttribute(node));
break;
case "distinct":
aggsQ.setAttributeDistinct(getAttribute(node));
break;
default:
throw new MolgenisQueryException(String.format(
"RSQL query selector [%s] not allowed in aggregates query, use ['x', 'y' or 'distinct']",
selector));
}
return aggsQ;
}
private Attribute getAttribute(ComparisonNode node)
{
List<String> args = node.getArguments();
if (args.size() != 1)
{
throw new MolgenisQueryException(
String.format("RSQL query value must have exactly one value instead of [%s]",
StringUtils.join(args, ',')));
}
String attrName = args.iterator().next();
String[] attrTokens = attrName.split("\\.");
Attribute attr = entityType.getAttribute(attrTokens[0]);
if (attr == null)
{
throw new UnknownAttributeException("Unknown attribute [" + attrName + "]");
}
EntityType entityTypeAtDepth;
for (int i = 1; i < attrTokens.length; ++i)
{
entityTypeAtDepth = attr.getRefEntity();
attr = entityTypeAtDepth.getAttribute(attrTokens[i]);
if (attr == null)
{
throw new UnknownAttributeException("Unknown attribute [" + attrName + "]");
}
}
return attr;
}
}