#594 ElasticSearch - Add match / TextExpression support - move expressions onto ExpressionList (remove TextExpressionList)

This commit is contained in:
Robin Bygrave
2016-03-18 12:51:39 +13:00
parent cb347ff5fa
commit 636acc61e5
16 changed files with 305 additions and 359 deletions
@@ -357,6 +357,6 @@ public interface ExpressionFactory {
* This is doc store Elastic only.
* </p>
*/
<T> TextJunction<T> textJunction(Query<T> query, TextExpressionList<T> parent, TextJunction.Type type);
<T> Junction<T> textJunction(Query<T> query, ExpressionList<T> parent, Junction.Type type);
}
@@ -1,5 +1,10 @@
package com.avaje.ebean;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
import com.avaje.ebean.search.TextQueryString;
import com.avaje.ebean.search.TextSimple;
import org.jetbrains.annotations.Nullable;
import javax.persistence.NonUniqueResultException;
@@ -842,6 +847,47 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> not(Expression exp);
/**
* Add a match expression.
*
* @param propertyName The property name for the match
* @param search The search value
*/
ExpressionList<T> match(String propertyName, String search);
/**
* Add a match expression with options.
*
* @param propertyName The property name for the match
* @param search The search value
*/
ExpressionList<T> match(String propertyName, String search, Match options);
/**
* Add a multi-match expression.
*/
ExpressionList<T> multiMatch(String search, String... properties);
/**
* Add a multi-match expression using options.
*/
ExpressionList<T> multiMatch(String search, MultiMatch options);
/**
* Add a simple query string expression.
*/
ExpressionList<T> textSimple(String search, TextSimple options);
/**
* Add a query string expression.
*/
ExpressionList<T> textQueryString(String search, TextQueryString options);
/**
* Add common terms expression.
*/
ExpressionList<T> textCommonTerms(String search, TextCommonTerms options);
/**
* Return a list of expressions that will be joined by AND's.
*/
@@ -861,4 +907,33 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> endJunction();
/**
* Start a list of expressions that will be joined by MUST.
*/
Junction<T> must();
/**
* Start a list of expressions that will be joined by SHOULD.
*/
Junction<T> should();
/**
* Start a list of expressions that will be joined by MUST NOT.
*/
Junction<T> mustNot();
/**
* End the list of MUST expressions.
*/
ExpressionList<T> endMust();
/**
* End the list of SHOULD expressions.
*/
ExpressionList<T> endShould();
/**
* End the list of MUST NOT expressions.
*/
ExpressionList<T> endMustNot();
}
+59 -15
View File
@@ -9,25 +9,25 @@ package com.avaje.ebean;
* <p>
* Note: where() always takes you to the top level WHERE expression list.
* </p>
*
*
* <pre class="code">
* Query q =
* Ebean.find(Person.class)
* .where().disjunction()
* .like(&quot;name&quot;, &quot;Rob%&quot;)
* .eq(&quot;status&quot;, Status.NEW)
*
*
* // where() returns us to the top level expression list
* .where().gt(&quot;id&quot;, 10);
*
*
* // read as...
* // where ( ((name like Rob%) or (status = NEW)) AND (id &gt; 10) )
* </pre>
*
*
* <p>
* Note: endJunction() takes you to the parent expression list
* </p>
*
*
* <pre class="code">
* Query q =
* Ebean.find(Person.class)
@@ -35,22 +35,22 @@ package com.avaje.ebean;
* .like(&quot;name&quot;, &quot;Rob%&quot;)
* .eq(&quot;status&quot;, Status.NEW)
* .endJunction()
*
*
* // endJunction().. takes us to the 'parent' expression list
* // which in this case is the top level (same as where())
*
*
* .gt(&quot;id&quot;, 10);
*
*
* // read as...
* // where ( ((name like Rob%) or (status = NEW)) AND (id &gt; 10) )
* </pre>
*
*
* <p>
* Example of a nested disjunction.
* </p>
*
*
* <pre class="code">
* Query&lt;Customer&gt; q =
* Query&lt;Customer&gt; q =
* Ebean.find(Customer.class)
* .where()
* .disjunction()
@@ -63,16 +63,60 @@ package com.avaje.ebean;
* .gt(&quot;id&quot;, 0)
* .endJunction()
* .order().asc(&quot;name&quot;);
*
*
* q.findList();
* String s = q.getGeneratedSql();
*
*
* // this produces an expression like:
*
*
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id &gt; ? )
*
*
* </pre>
*/
public interface Junction<T> extends Expression, ExpressionList<T> {
/**
* The type of Junction used in full text expressions.
*/
enum Type {
/**
* AND group.
*/
AND(" and "),
/**
* OR group.
*/
OR(" or "),
/**
* Text search AND group.
*/
MUST("must"),
/**
* Text search NOT group.
*/
MUST_NOT("must_not"),
/**
* Text search OR group.
*/
SHOULD("should");
String literal;
Type(String literal) {
this.literal = literal;
}
/**
* Return the literal value for this type.
*/
public String literal() {
return literal;
}
}
}
+1 -1
View File
@@ -1060,7 +1060,7 @@ public interface Query<T> {
* ElasticSearch query.
* </p>
*/
TextExpressionList<T> text();
ExpressionList<T> text();
/**
* This applies a filter on the 'many' property list rather than the root
@@ -1,88 +0,0 @@
package com.avaje.ebean;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
import com.avaje.ebean.search.TextQueryString;
import com.avaje.ebean.search.TextSimple;
/**
* An list of Full text query expressions.
* <p>
* For ElasticSearch these expression go into the "query" section rather than the "filter" section.
* </p>
*/
public interface TextExpressionList<T> extends ExpressionList<T> {
/**
* Add a match expression.
*
* @param propertyName The property name for the match
* @param search The search value
*/
TextExpressionList<T> match(String propertyName, String search);
/**
* Add a match expression with options.
*
* @param propertyName The property name for the match
* @param search The search value
*/
TextExpressionList<T> match(String propertyName, String search, Match options);
/**
* Add a multi-match expression.
*/
TextExpressionList<T> multiMatch(String search, String... properties);
/**
* Add a multi-match expression using options.
*/
TextExpressionList<T> multiMatch(String search, MultiMatch options);
/**
* Add a simple query string expression.
*/
TextExpressionList<T> textSimple(String search, TextSimple options);
/**
* Add a query string expression.
*/
TextExpressionList<T> textQueryString(String search, TextQueryString options);
/**
* Add common terms expression.
*/
TextExpressionList<T> textCommonTerms(String search, TextCommonTerms options);
/**
* Start a list of expressions that will be joined by MUST.
*/
TextJunction<T> must();
/**
* Start a list of expressions that will be joined by SHOULD.
*/
TextJunction<T> should();
/**
* Start a list of expressions that will be joined by MUST NOT.
*/
TextJunction<T> mustNot();
/**
* End the list of MUST expressions.
*/
TextExpressionList<T> endMust();
/**
* End the list of SHOULD expressions.
*/
TextExpressionList<T> endShould();
/**
* End the list of MUST NOT expressions.
*/
TextExpressionList<T> endMustNot();
}
@@ -1,41 +0,0 @@
package com.avaje.ebean;
/**
* A Full text MUST, MUST NOT or SHOULD group of expressions.
*/
public interface TextJunction<T> extends Junction<T>, TextExpressionList<T> {
/**
* The type of Junction used in full text expressions.
*/
enum Type {
/**
* Logically a AND group.
*/
MUST("must"),
/**
* Logically a NOT group.
*/
MUST_NOT("must_not"),
/**
* Logically a OR group.
*/
SHOULD("should");
String literal;
Type(String literal) {
this.literal = literal;
}
/**
* Return the literal value for this type.
*/
public String literal() {
return literal;
}
}
}
@@ -1,18 +1,17 @@
package com.avaje.ebeaninternal.api;
import com.avaje.ebean.TextJunction;
import com.avaje.ebean.Junction;
import com.avaje.ebeaninternal.server.expression.DocQueryContext;
import java.io.IOException;
/**
* SPI extension to the full text junctions (MUST, MUST NOT, SHOULD).
* SPI methods for Junction.
*/
public interface SpiTextJunction<T> extends TextJunction<T> {
public interface SpiJunction<T> extends Junction<T> {
/**
* Write the junction expression to the query context.
* Write the Junction taking into account it is implied.
*/
void writeDocQueryJunction(DocQueryContext context) throws IOException;
}
@@ -1,10 +0,0 @@
package com.avaje.ebeaninternal.api;
import com.avaje.ebean.TextExpressionList;
/**
* SPI extensions to Full text expression list.
*/
public interface SpiTextExpressionList<T> extends TextExpressionList<T> {
}
@@ -18,31 +18,33 @@ public abstract class AbstractTextExpression extends AbstractExpression {
@Override
public void addSql(SpiExpressionRequest request) {
throw new IllegalStateException("Not implemented - DocStore/Elastic only");
// do nothing, only execute against document store
}
@Override
public void addBindValues(SpiExpressionRequest request) {
throw new IllegalStateException("Not implemented - DocStore/Elastic only");
// do nothing, only execute against document store
}
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
throw new IllegalStateException("Not implemented - query plan caching done explicitly by the doc store");
// do nothing, only execute against document store
}
@Override
public int queryBindHash() {
throw new IllegalStateException("Not implemented - query plan caching done explicitly by the doc store");
return 0;
}
@Override
public boolean isSameByPlan(SpiExpression other) {
throw new IllegalStateException("Not implemented - query plan caching done explicitly by the doc store");
// do not compare by plan / bind values (this way)
return false;
}
@Override
public boolean isSameByBind(SpiExpression other) {
throw new IllegalStateException("Not implemented - query plan caching done explicitly by the doc store");
// do not compare by plan / bind values (this way)
return false;
}
}
@@ -1,113 +0,0 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Query;
import com.avaje.ebean.TextExpressionList;
import com.avaje.ebean.TextJunction;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
import com.avaje.ebean.search.TextQueryString;
import com.avaje.ebean.search.TextSimple;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiTextJunction;
import java.io.IOException;
import java.util.List;
/**
* Implementation of SpiTextJunction (Must, Must Not or Should group).
*/
class DTextJunction<T> extends JunctionExpression<T> implements SpiTextJunction<T> {
private final TextJunction.Type type;
DTextJunction(Query<T> query, TextExpressionList<T> parent, TextJunction.Type type) {
super(query, parent);
this.type = type;
}
@Override
public void writeDocQueryJunction(DocQueryContext context) throws IOException {
context.startBoolGroupList(type);
List<SpiExpression> list = exprList.internalList();
for (int i = 0; i < list.size(); i++) {
list.get(i).writeDocQuery(context);
}
context.endBoolGroupList();
}
@Override
public SpiExpression copyForPlanKey() {
return this;
}
@Override
public TextExpressionList<T> match(String propertyName, String search) {
return match(propertyName, search, null);
}
@Override
public TextExpressionList<T> match(String propertyName, String search, Match options) {
return exprList.match(propertyName, search, options);
}
@Override
public TextExpressionList<T> multiMatch(String query, String... properties) {
return exprList.multiMatch(query, properties);
}
@Override
public TextExpressionList<T> multiMatch(String query, MultiMatch options) {
return exprList.multiMatch(query, options);
}
@Override
public TextExpressionList<T> textSimple(String search, TextSimple options) {
return exprList.textSimple(search, options);
}
@Override
public TextExpressionList<T> textQueryString(String search, TextQueryString options) {
return exprList.textQueryString(search, options);
}
@Override
public TextExpressionList<T> textCommonTerms(String search, TextCommonTerms options) {
return exprList.textCommonTerms(search, options);
}
@Override
public TextJunction<T> must() {
return exprList.must();
}
@Override
public TextJunction<T> should() {
return exprList.should();
}
@Override
public TextJunction<T> mustNot() {
return exprList.mustNot();
}
@Override
public TextExpressionList<T> endMust() {
return endTextJunction();
}
@Override
public TextExpressionList<T> endShould() {
return endTextJunction();
}
@Override
public TextExpressionList<T> endMustNot() {
return endTextJunction();
}
private TextExpressionList<T> endTextJunction() {
return exprList.endTextJunction();
}
}
@@ -7,8 +7,6 @@ import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.Junction;
import com.avaje.ebean.LikeType;
import com.avaje.ebean.Query;
import com.avaje.ebean.TextExpressionList;
import com.avaje.ebean.TextJunction;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
@@ -438,7 +436,6 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* Return a list of expressions that will be joined by AND's.
*/
public <T> Junction<T> conjunction(Query<T> query) {
return new JunctionExpression.Conjunction<T>(query, query.where());
}
@@ -446,7 +443,6 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* Return a list of expressions that will be joined by OR's.
*/
public <T> Junction<T> disjunction(Query<T> query) {
return new JunctionExpression.Disjunction<T>(query, query.where());
}
@@ -454,7 +450,6 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* Return a list of expressions that will be joined by AND's.
*/
public <T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent) {
return new JunctionExpression.Conjunction<T>(query, parent);
}
@@ -462,7 +457,6 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* Return a list of expressions that will be joined by OR's.
*/
public <T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent) {
return new JunctionExpression.Disjunction<T>(query, parent);
}
@@ -470,7 +464,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
* Create and return a Full text junction (Must, Must Not or Should).
*/
@Override
public <T> TextJunction<T> textJunction(Query<T> query, TextExpressionList<T> parent, TextJunction.Type type) {
return new DTextJunction<T>(query, parent, type);
public <T> Junction<T> textJunction(Query<T> query, ExpressionList<T> parent, Junction.Type type) {
return new JunctionExpression.TextJunction<T>(query, parent, type);
}
}
@@ -13,8 +13,7 @@ import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.api.SpiTextExpressionList;
import com.avaje.ebeaninternal.api.SpiTextJunction;
import com.avaje.ebeaninternal.api.SpiJunction;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.io.IOException;
@@ -28,13 +27,13 @@ import java.util.Set;
/**
* Default implementation of ExpressionList.
*/
public class DefaultExpressionList<T> implements SpiExpressionList<T>, SpiTextExpressionList<T> {
public class DefaultExpressionList<T> implements SpiExpressionList<T> {
protected final List<SpiExpression> list;
protected final Query<T> query;
protected final TextExpressionList<T> parentExprList;
protected final ExpressionList<T> parentExprList;
protected transient ExpressionFactory expr;
@@ -54,19 +53,19 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T>, SpiTextEx
this(query, query.getExpressionFactory(), null, new ArrayList<SpiExpression>(), true);
}
public DefaultExpressionList(Query<T> query, TextExpressionList<T> parentExprList) {
public DefaultExpressionList(Query<T> query, ExpressionList<T> parentExprList) {
this(query, query.getExpressionFactory(), parentExprList);
}
public DefaultExpressionList(Query<T> query, ExpressionFactory expr, TextExpressionList<T> parentExprList) {
public DefaultExpressionList(Query<T> query, ExpressionFactory expr, ExpressionList<T> parentExprList) {
this(query, expr, parentExprList, new ArrayList<SpiExpression>());
}
protected DefaultExpressionList(Query<T> query, ExpressionFactory expr, TextExpressionList<T> parentExprList, List<SpiExpression> list) {
protected DefaultExpressionList(Query<T> query, ExpressionFactory expr, ExpressionList<T> parentExprList, List<SpiExpression> list) {
this(query, expr, parentExprList, list, false);
}
private DefaultExpressionList(Query<T> query, ExpressionFactory expr, TextExpressionList<T> parentExprList, List<SpiExpression> list, boolean textRoot) {
private DefaultExpressionList(Query<T> query, ExpressionFactory expr, ExpressionList<T> parentExprList, List<SpiExpression> list, boolean textRoot) {
this.textRoot = textRoot;
this.list = list;
this.query = query;
@@ -104,20 +103,20 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T>, SpiTextEx
int size = list.size();
SpiExpression first = list.get(0);
boolean explicitBool = first instanceof SpiTextJunction<?>;
boolean explicitBool = first instanceof SpiJunction<?>;
boolean implicitBool = !explicitBool && size > 1;
if (implicitBool || explicitBool) {
context.startBoolGroup();
}
if (implicitBool) {
context.startBoolGroupList(TextJunction.Type.SHOULD);
context.startBoolGroupList(Junction.Type.SHOULD);
}
for (int i = 0; i < size; i++) {
SpiExpression expr = list.get(i);
if (explicitBool) {
try {
((SpiTextJunction<?>) expr).writeDocQueryJunction(context);
((SpiJunction<?>)expr).writeDocQueryJunction(context);
} catch (ClassCastException e) {
throw new IllegalStateException("The top level text() expressions should be all be 'Must', 'Should' or 'Must Not' or none of them should be.", e);
}
@@ -208,7 +207,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T>, SpiTextEx
return parentExprList == null ? this : parentExprList;
}
protected TextExpressionList<T> endTextJunction() {
protected ExpressionList<T> endTextJunction() {
return parentExprList == null ? this : parentExprList;
}
@@ -647,8 +646,8 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T>, SpiTextEx
return this;
}
public TextJunction<T> textJunction(TextJunction.Type type) {
TextJunction<T> junction = expr.textJunction(query, this, type);
public Junction<T> textJunction(Junction.Type type) {
Junction<T> junction = expr.textJunction(query, this, type);
add(junction);
return junction;
}
@@ -858,72 +857,77 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T>, SpiTextEx
}
@Override
public TextExpressionList<T> match(String propertyName, String search) {
public ExpressionList<T> match(String propertyName, String search) {
return match(propertyName, search, null);
}
@Override
public TextExpressionList<T> match(String propertyName, String search, Match options) {
public ExpressionList<T> match(String propertyName, String search, Match options) {
add(expr.textMatch(propertyName, search, options));
setUseDocStore(true);
return this;
}
@Override
public TextExpressionList<T> multiMatch(String query, String... fields) {
return multiMatch(query, new MultiMatch().fields(fields));
public ExpressionList<T> multiMatch(String query, String... fields) {
return multiMatch(query, MultiMatch.fields(fields));
}
@Override
public TextExpressionList<T> multiMatch(String query, MultiMatch options) {
public ExpressionList<T> multiMatch(String query, MultiMatch options) {
setUseDocStore(true);
add(expr.textMultiMatch(query, options));
return this;
}
@Override
public TextExpressionList<T> textSimple(String search, TextSimple options) {
public ExpressionList<T> textSimple(String search, TextSimple options) {
setUseDocStore(true);
add(expr.textSimple(search, options));
return this;
}
@Override
public TextExpressionList<T> textQueryString(String search, TextQueryString options) {
public ExpressionList<T> textQueryString(String search, TextQueryString options) {
setUseDocStore(true);
add(expr.textQueryString(search, options));
return this;
}
@Override
public TextExpressionList<T> textCommonTerms(String search, TextCommonTerms options) {
public ExpressionList<T> textCommonTerms(String search, TextCommonTerms options) {
setUseDocStore(true);
add(expr.textCommonTerms(search, options));
return this;
}
@Override
public TextJunction<T> must() {
return textJunction(TextJunction.Type.MUST);
public Junction<T> must() {
return textJunction(Junction.Type.MUST);
}
@Override
public TextJunction<T> should() {
return textJunction(TextJunction.Type.SHOULD);
public Junction<T> should() {
return textJunction(Junction.Type.SHOULD);
}
@Override
public TextJunction<T> mustNot() {
return textJunction(TextJunction.Type.MUST_NOT);
public Junction<T> mustNot() {
return textJunction(Junction.Type.MUST_NOT);
}
@Override
public TextExpressionList<T> endMust() {
public ExpressionList<T> endMust() {
return endTextJunction();
}
@Override
public TextExpressionList<T> endShould() {
public ExpressionList<T> endShould() {
return endTextJunction();
}
@Override
public TextExpressionList<T> endMustNot() {
public ExpressionList<T> endMustNot() {
return endTextJunction();
}
}
@@ -1,7 +1,7 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Junction;
import com.avaje.ebean.LikeType;
import com.avaje.ebean.TextJunction;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
@@ -130,7 +130,7 @@ public interface DocQueryContext {
/**
* Start a Must, Must Not or Should list.
*/
void startBoolGroupList(TextJunction.Type type) throws IOException;
void startBoolGroupList(Junction.Type type) throws IOException;
/**
* End a Must, Must Not or Should list.
@@ -2,11 +2,17 @@ package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.*;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
import com.avaje.ebean.search.TextQueryString;
import com.avaje.ebean.search.TextSimple;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.api.SpiJunction;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.io.IOException;
@@ -19,20 +25,30 @@ import java.util.Set;
/**
* Junction implementation.
*/
abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, ExpressionList<T> {
abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> {
static final String OR = " or ";
static class TextJunction<T> extends JunctionExpression<T> {
static final String AND = " and ";
TextJunction(Query<T> query, ExpressionList<T> parent, TextJunction.Type type) {
super(type, query, parent);
}
TextJunction(TextJunction.Type type, DefaultExpressionList<T> expressionList) {
super(type, expressionList);
}
@Override
public SpiExpression copyForPlanKey() {
return new TextJunction<T>(type, exprList.copyForPlanKey());
}
}
static class Conjunction<T> extends JunctionExpression<T> {
Conjunction(Query<T> query, ExpressionList<T> parent) {
super(false, AND, query, parent);
super(Type.AND, query, parent);
}
Conjunction(DefaultExpressionList<T> expressionList) {
super(false, AND, expressionList);
super(Type.AND, expressionList);
}
@Override
public SpiExpression copyForPlanKey() {
@@ -43,11 +59,11 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
static class Disjunction<T> extends JunctionExpression<T> {
Disjunction(Query<T> query, ExpressionList<T> parent) {
super(true, OR, query, parent);
super(Type.OR, query, parent);
}
Disjunction(DefaultExpressionList<T> expressionList) {
super(true, OR, expressionList);
super(Type.OR, expressionList);
}
@Override
@@ -58,37 +74,24 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
protected final DefaultExpressionList<T> exprList;
private final String joinType;
protected final Junction.Type type;
/**
* If true then a disjunction which means outer joins are required.
*/
private final boolean disjunction;
JunctionExpression(Query<T> query, TextExpressionList<T> parent) {
this.disjunction = true;
this.joinType = OR;
JunctionExpression(Junction.Type type, Query<T> query, ExpressionList<T> parent) {
this.type = type;
this.exprList = new DefaultExpressionList<T>(query, parent);
}
JunctionExpression(boolean disjunction, String joinType, Query<T> query, ExpressionList<T> parent) {
this.disjunction = disjunction;
this.joinType = joinType;
this.exprList = new DefaultExpressionList<T>(query, (TextExpressionList<T>)parent);
}
/**
* Construct for copyForPlanKey.
*/
JunctionExpression(boolean disjunction, String joinType, DefaultExpressionList<T> exprList) {
this.disjunction = disjunction;
this.joinType = joinType;
JunctionExpression(Junction.Type type, DefaultExpressionList<T> exprList) {
this.type = type;
this.exprList = exprList;
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.startBool(!disjunction);
context.startBool(type == Type.AND);
List<SpiExpression> list = exprList.internalList();
for (int i = 0; i < list.size(); i++) {
list.get(i).writeDocQuery(context);
@@ -96,6 +99,16 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
context.endBool();
}
@Override
public void writeDocQueryJunction(DocQueryContext context) throws IOException {
context.startBoolGroupList(type);
List<SpiExpression> list = exprList.internalList();
for (int i = 0; i < list.size(); i++) {
list.get(i).writeDocQuery(context);
}
context.endBoolGroupList();
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -103,7 +116,7 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
// get the current state for 'require outer joins'
boolean parentOuterJoins = manyWhereJoin.isRequireOuterJoins();
if (disjunction) {
if (type == Type.OR) {
// turn on outer joins required for disjunction expressions
manyWhereJoin.setRequireOuterJoins(true);
}
@@ -111,7 +124,7 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
for (int i = 0; i < list.size(); i++) {
list.get(i).containsMany(desc, manyWhereJoin);
}
if (disjunction && !parentOuterJoins) {
if (type == Type.OR && !parentOuterJoins) {
// restore state to not forcing outer joins
manyWhereJoin.setRequireOuterJoins(false);
}
@@ -155,7 +168,7 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
for (int i = 0; i < list.size(); i++) {
SpiExpression item = list.get(i);
if (i > 0) {
request.append(joinType);
request.append(type.literal());
}
item.addSql(request);
}
@@ -177,7 +190,7 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
*/
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
builder.add(JunctionExpression.class).add(joinType);
builder.add(JunctionExpression.class).add(type);
List<SpiExpression> list = exprList.internalList();
for (int i = 0; i < list.size(); i++) {
list.get(i).queryPlanHash(builder);
@@ -204,15 +217,82 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
}
JunctionExpression that = (JunctionExpression) other;
return joinType.equals(that.joinType)
&& exprList.isSameByPlan(that.exprList);
return type == that.type && exprList.isSameByPlan(that.exprList);
}
@Override
public boolean isSameByBind(SpiExpression other) {
JunctionExpression that = (JunctionExpression) other;
return joinType.equals(that.joinType)
&& exprList.isSameByBind(that.exprList);
return type == that.type && exprList.isSameByBind(that.exprList);
}
@Override
public ExpressionList<T> match(String propertyName, String search) {
return match(propertyName, search, null);
}
@Override
public ExpressionList<T> match(String propertyName, String search, Match options) {
return exprList.match(propertyName, search, options);
}
@Override
public ExpressionList<T> multiMatch(String query, String... properties) {
return exprList.multiMatch(query, properties);
}
@Override
public ExpressionList<T> multiMatch(String query, MultiMatch options) {
return exprList.multiMatch(query, options);
}
@Override
public ExpressionList<T> textSimple(String search, TextSimple options) {
return exprList.textSimple(search, options);
}
@Override
public ExpressionList<T> textQueryString(String search, TextQueryString options) {
return exprList.textQueryString(search, options);
}
@Override
public ExpressionList<T> textCommonTerms(String search, TextCommonTerms options) {
return exprList.textCommonTerms(search, options);
}
@Override
public Junction<T> must() {
return exprList.must();
}
@Override
public Junction<T> should() {
return exprList.should();
}
@Override
public Junction<T> mustNot() {
return exprList.mustNot();
}
@Override
public ExpressionList<T> endMust() {
return endTextJunction();
}
@Override
public ExpressionList<T> endShould() {
return endTextJunction();
}
@Override
public ExpressionList<T> endMustNot() {
return endTextJunction();
}
private ExpressionList<T> endTextJunction() {
return exprList.endTextJunction();
}
@Override
@@ -1316,7 +1316,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
@Override
public TextExpressionList text() {
public ExpressionList<T> text() {
if (textExpressions == null) {
useDocStore = true;
textExpressions = new DefaultExpressionList<T>(this);
+3 -3
View File
@@ -77,9 +77,9 @@
<logger name="com.avaje.ebean" level="INFO"/>
<logger name="org.avaje.ebean" level="INFO"/>
<!--<logger name="org.avaje.ebean.SQL" level="TRACE"/>-->
<!--<logger name="org.avaje.ebean.TXN" level="TRACE"/>-->
<!--<logger name="org.avaje.ebean.SUM" level="TRACE"/>-->
<logger name="org.avaje.ebean.SQL" level="TRACE"/>
<logger name="org.avaje.ebean.TXN" level="TRACE"/>
<logger name="org.avaje.ebean.SUM" level="TRACE"/>
<!--<logger name="org.avaje.ebean.ELA" level="TRACE"/>-->