EQL - Simplify nested query where expressions after parsing

This commit is contained in:
Robin Bygrave
2016-07-12 22:51:02 +12:00
parent 84b37fb014
commit ceab95e6c2
18 changed files with 145 additions and 20 deletions
+21 -11
View File
@@ -59,11 +59,11 @@ package com.avaje.ebean;
* .and()
* .startsWith("name", "r")
* .eq("anniversary", onAfter)
* .endJunction()
* .endAnd()
* .and()
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endJunction()
* .endAnd()
* .order().asc("name");
*
* q.findList();
@@ -84,39 +84,41 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
/**
* AND group.
*/
AND(" and ", ""),
AND(" and ", "", false),
/**
* OR group.
*/
OR(" or ", ""),
OR(" or ", "", false),
/**
* NOT group.
*/
NOT(" and ", "not "),
NOT(" and ", "not ", false),
/**
* Text search AND group.
*/
MUST("must", ""),
MUST("must", "", true),
/**
* Text search NOT group.
*/
MUST_NOT("must_not", ""),
MUST_NOT("must_not", "", true),
/**
* Text search OR group.
*/
SHOULD("should", "");
SHOULD("should", "", true);
String prefix;
String literal;
private String prefix;
private String literal;
private boolean text;
Type(String literal, String prefix) {
Type(String literal, String prefix, boolean text) {
this.literal = literal;
this.prefix = prefix;
this.text = text;
}
/**
@@ -132,6 +134,14 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
public String prefix() {
return prefix;
}
/**
* Return true if this is a text type.
*/
public boolean isText() {
return text;
}
}
}
@@ -13,7 +13,12 @@ import java.io.IOException;
*/
public interface SpiExpression extends Expression {
/**
/**
* Simplify nested expressions if possible.
*/
void simplify();
/**
* Write the expression as an elastic search expression.
*/
void writeDocQuery(DocQueryContext context) throws IOException;
@@ -693,4 +693,8 @@ public interface SpiQuery<T> extends Query<T> {
*/
OrmUpdateProperties getUpdateProperties();
/**
* Simplify nested expression lists where possible.
*/
void simplifyExpressions();
}
@@ -21,6 +21,11 @@ public abstract class AbstractExpression implements SpiExpression {
this.propName = propName;
}
@Override
public void simplify() {
// do nothing
}
@Override
public Object getIdEqualTo(String idName) {
// override on SimpleExpression
@@ -88,6 +88,11 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
}
}
@Override
public void simplify() {
// do nothing
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
if (!list.isEmpty()) {
@@ -97,6 +97,16 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
}
void simplifyEntries() {
for (SpiExpression element : list) {
element.simplify();
}
}
public void simplify() {
simplifyEntries();
}
/**
* Write being aware if it is the Top level "text" expressions.
* <p>
@@ -36,6 +36,11 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress
this.subQuery = null;
}
@Override
public void simplify() {
// do nothing
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
throw new IllegalStateException("Not supported");
@@ -38,6 +38,11 @@ class InQueryExpression extends AbstractExpression implements UnsupportedDocStor
this.bindParams = bindParams;
}
@Override
public void simplify() {
// do nothing
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
throw new IllegalStateException("Not supported");
@@ -39,9 +39,9 @@ import java.util.Set;
*/
class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> {
protected final DefaultExpressionList<T> exprList;
protected DefaultExpressionList<T> exprList;
protected final Junction.Type type;
protected Junction.Type type;
JunctionExpression(Junction.Type type, Query<T> query, ExpressionList<T> parent) {
this.type = type;
@@ -56,6 +56,31 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
this.exprList = exprList;
}
/**
* Simplify nested expressions where possible.
* <p>
* This is expected to only used after expressions are built via query language parsing.
* </p>
*/
public void simplify() {
exprList.simplifyEntries();
List<SpiExpression> list = exprList.list;
if (list.size() == 1 && list.get(0) instanceof JunctionExpression) {
JunctionExpression nested = (JunctionExpression)list.get(0);
if (type == Type.AND && !nested.type.isText()) {
// and (and (a, b, c)) -> and (a, b, c)
// and (not (a, b, c)) -> not (a, b, c)
// and (or (a, b, c)) -> or (a, b, c)
this.exprList = nested.exprList;
this.type = nested.type;
} else if (type == Type.NOT && nested.type == Type.AND) {
// not (and (a, b, c)) -> not (a, b, c)
this.exprList = nested.exprList;
}
}
}
public SpiExpression copyForPlanKey() {
return new JunctionExpression<T>(type, exprList.copyForPlanKey());
}
@@ -57,6 +57,11 @@ abstract class LogicExpression implements SpiExpression {
this.expTwo = (SpiExpression) expTwo;
}
@Override
public void simplify() {
// do nothing
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
@@ -24,6 +24,11 @@ class NestedPathWrapperExpression implements SpiExpression {
this.delegate = delegate;
}
@Override
public void simplify() {
// do nothing
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.startNested(nestedPath);
@@ -8,6 +8,11 @@ import com.avaje.ebeaninternal.api.SpiExpression;
*/
abstract class NonPrepareExpression implements SpiExpression {
@Override
public void simplify() {
// do nothing
}
@Override
public void prepareExpression(BeanQueryRequest<?> request) {
// do nothing
@@ -17,6 +17,11 @@ class NoopExpression implements SpiExpression {
protected static final NoopExpression INSTANCE = new NoopExpression();
@Override
public void simplify() {
// do nothing
}
@Override
public SpiExpression copyForPlanKey() {
return this;
@@ -22,6 +22,11 @@ final class NotExpression implements SpiExpression {
this.exp = (SpiExpression) exp;
}
@Override
public void simplify() {
// do nothing
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.startBoolMustNot();
@@ -27,8 +27,8 @@ class EqlAdapter<T> extends EQLBaseListener {
private boolean textMode;
public EqlAdapter(Query<T> query) {
this.query = (SpiQuery<T>)query;
public EqlAdapter(SpiQuery<T> query) {
this.query = query;
this.helper = new EqlAdapterHelper(this);
}
@@ -1,6 +1,6 @@
package com.avaje.ebeaninternal.server.grammer;
import com.avaje.ebean.Query;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.grammer.antlr.EQLLexer;
import com.avaje.ebeaninternal.server.grammer.antlr.EQLParser;
import org.antlr.v4.runtime.ANTLRInputStream;
@@ -9,7 +9,7 @@ import org.antlr.v4.runtime.tree.ParseTreeWalker;
public class EqlParser {
public static <T> void parse(String raw, Query<T> query) {
public static <T> void parse(String raw, SpiQuery<T> query) {
EQLLexer lexer = new EQLLexer(new ANTLRInputStream(raw));
CommonTokenStream tokens = new CommonTokenStream(lexer);
@@ -20,5 +20,7 @@ public class EqlParser {
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(adapter, context);
query.simplifyExpressions();
}
}
@@ -1349,6 +1349,13 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return whereExpressions;
}
@Override
public void simplifyExpressions() {
if (whereExpressions != null) {
whereExpressions.simplify();
}
}
@Override
public DefaultOrmQuery<T> having(Expression expression) {
having().add(expression);