From 636acc61e59c796af9b6324532622dcbb5a4b5b5 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 18 Mar 2016 12:51:39 +1300 Subject: [PATCH] #594 ElasticSearch - Add match / TextExpression support - move expressions onto ExpressionList (remove TextExpressionList) --- .../com/avaje/ebean/ExpressionFactory.java | 2 +- .../java/com/avaje/ebean/ExpressionList.java | 75 +++++++++ src/main/java/com/avaje/ebean/Junction.java | 74 +++++++-- src/main/java/com/avaje/ebean/Query.java | 2 +- .../com/avaje/ebean/TextExpressionList.java | 88 ----------- .../java/com/avaje/ebean/TextJunction.java | 41 ----- ...{SpiTextJunction.java => SpiJunction.java} | 9 +- .../api/SpiTextExpressionList.java | 10 -- .../expression/AbstractTextExpression.java | 14 +- .../server/expression/DTextJunction.java | 113 ------------- .../expression/DefaultExpressionFactory.java | 10 +- .../expression/DefaultExpressionList.java | 66 ++++---- .../server/expression/DocQueryContext.java | 4 +- .../server/expression/JunctionExpression.java | 148 ++++++++++++++---- .../server/querydefn/DefaultOrmQuery.java | 2 +- src/test/resources/logback-test.xml | 6 +- 16 files changed, 305 insertions(+), 359 deletions(-) delete mode 100644 src/main/java/com/avaje/ebean/TextExpressionList.java delete mode 100644 src/main/java/com/avaje/ebean/TextJunction.java rename src/main/java/com/avaje/ebeaninternal/api/{SpiTextJunction.java => SpiJunction.java} (50%) delete mode 100644 src/main/java/com/avaje/ebeaninternal/api/SpiTextExpressionList.java delete mode 100644 src/main/java/com/avaje/ebeaninternal/server/expression/DTextJunction.java diff --git a/src/main/java/com/avaje/ebean/ExpressionFactory.java b/src/main/java/com/avaje/ebean/ExpressionFactory.java index 17bd817d3..0694886e4 100644 --- a/src/main/java/com/avaje/ebean/ExpressionFactory.java +++ b/src/main/java/com/avaje/ebean/ExpressionFactory.java @@ -357,6 +357,6 @@ public interface ExpressionFactory { * This is doc store Elastic only. *

*/ - TextJunction textJunction(Query query, TextExpressionList parent, TextJunction.Type type); + Junction textJunction(Query query, ExpressionList parent, Junction.Type type); } diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index 6577751e6..80843ae26 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -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 { */ ExpressionList not(Expression exp); + /** + * Add a match expression. + * + * @param propertyName The property name for the match + * @param search The search value + */ + ExpressionList 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 match(String propertyName, String search, Match options); + + /** + * Add a multi-match expression. + */ + ExpressionList multiMatch(String search, String... properties); + + /** + * Add a multi-match expression using options. + */ + ExpressionList multiMatch(String search, MultiMatch options); + + /** + * Add a simple query string expression. + */ + ExpressionList textSimple(String search, TextSimple options); + + /** + * Add a query string expression. + */ + ExpressionList textQueryString(String search, TextQueryString options); + + /** + * Add common terms expression. + */ + ExpressionList textCommonTerms(String search, TextCommonTerms options); + /** * Return a list of expressions that will be joined by AND's. */ @@ -861,4 +907,33 @@ public interface ExpressionList { */ ExpressionList endJunction(); + /** + * Start a list of expressions that will be joined by MUST. + */ + Junction must(); + + /** + * Start a list of expressions that will be joined by SHOULD. + */ + Junction should(); + + /** + * Start a list of expressions that will be joined by MUST NOT. + */ + Junction mustNot(); + + /** + * End the list of MUST expressions. + */ + ExpressionList endMust(); + + /** + * End the list of SHOULD expressions. + */ + ExpressionList endShould(); + + /** + * End the list of MUST NOT expressions. + */ + ExpressionList endMustNot(); } diff --git a/src/main/java/com/avaje/ebean/Junction.java b/src/main/java/com/avaje/ebean/Junction.java index ece8deeed..36a130ee7 100644 --- a/src/main/java/com/avaje/ebean/Junction.java +++ b/src/main/java/com/avaje/ebean/Junction.java @@ -9,25 +9,25 @@ package com.avaje.ebean; *

* Note: where() always takes you to the top level WHERE expression list. *

- * + * *
  * Query q =
  *     Ebean.find(Person.class)
  *         .where().disjunction()
  *         .like("name", "Rob%")
  *         .eq("status", Status.NEW)
- * 
+ *
  *         // where() returns us to the top level expression list
  *         .where().gt("id", 10);
- * 
+ *
  * // read as...
  * // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
  * 
- * + * *

* Note: endJunction() takes you to the parent expression list *

- * + * *
  * Query q =
  *     Ebean.find(Person.class)
@@ -35,22 +35,22 @@ package com.avaje.ebean;
  *         .like("name", "Rob%")
  *         .eq("status", Status.NEW)
  *         .endJunction()
- * 
+ *
  *         // endJunction().. takes us to the 'parent' expression list
  *         // which in this case is the top level (same as where())
- * 
+ *
  *         .gt("id", 10);
- * 
+ *
  * // read as...
  * // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
  * 
- * + * *

* Example of a nested disjunction. *

- * + * *
- * Query<Customer> q = 
+ * Query<Customer> q =
  *  Ebean.find(Customer.class)
  *      .where()
  *          .disjunction()
@@ -63,16 +63,60 @@ package com.avaje.ebean;
  *                  .gt("id", 0)
  *                  .endJunction()
  *      .order().asc("name");
- * 
+ *
  * q.findList();
  * String s = q.getGeneratedSql();
- * 
+ *
  *  // this produces an expression like:
- *  
+ *
  *  ( name like ? and c.anniversary = ? ) or (c.status = ?  and c.id > ? )
- * 
+ *
  * 
*/ public interface Junction extends Expression, ExpressionList { + /** + * 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; + } + } + } diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 2b6ebe314..fecc7eeb9 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -1060,7 +1060,7 @@ public interface Query { * ElasticSearch query. *

*/ - TextExpressionList text(); + ExpressionList text(); /** * This applies a filter on the 'many' property list rather than the root diff --git a/src/main/java/com/avaje/ebean/TextExpressionList.java b/src/main/java/com/avaje/ebean/TextExpressionList.java deleted file mode 100644 index 887e5a1ba..000000000 --- a/src/main/java/com/avaje/ebean/TextExpressionList.java +++ /dev/null @@ -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. - *

- * For ElasticSearch these expression go into the "query" section rather than the "filter" section. - *

- */ -public interface TextExpressionList extends ExpressionList { - - /** - * Add a match expression. - * - * @param propertyName The property name for the match - * @param search The search value - */ - TextExpressionList 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 match(String propertyName, String search, Match options); - - /** - * Add a multi-match expression. - */ - TextExpressionList multiMatch(String search, String... properties); - - /** - * Add a multi-match expression using options. - */ - TextExpressionList multiMatch(String search, MultiMatch options); - - /** - * Add a simple query string expression. - */ - TextExpressionList textSimple(String search, TextSimple options); - - /** - * Add a query string expression. - */ - TextExpressionList textQueryString(String search, TextQueryString options); - - /** - * Add common terms expression. - */ - TextExpressionList textCommonTerms(String search, TextCommonTerms options); - - /** - * Start a list of expressions that will be joined by MUST. - */ - TextJunction must(); - - /** - * Start a list of expressions that will be joined by SHOULD. - */ - TextJunction should(); - - /** - * Start a list of expressions that will be joined by MUST NOT. - */ - TextJunction mustNot(); - - /** - * End the list of MUST expressions. - */ - TextExpressionList endMust(); - - /** - * End the list of SHOULD expressions. - */ - TextExpressionList endShould(); - - /** - * End the list of MUST NOT expressions. - */ - TextExpressionList endMustNot(); - -} diff --git a/src/main/java/com/avaje/ebean/TextJunction.java b/src/main/java/com/avaje/ebean/TextJunction.java deleted file mode 100644 index 537d0bbb4..000000000 --- a/src/main/java/com/avaje/ebean/TextJunction.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.avaje.ebean; - -/** - * A Full text MUST, MUST NOT or SHOULD group of expressions. - */ -public interface TextJunction extends Junction, TextExpressionList { - - /** - * 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; - } - } -} diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiTextJunction.java b/src/main/java/com/avaje/ebeaninternal/api/SpiJunction.java similarity index 50% rename from src/main/java/com/avaje/ebeaninternal/api/SpiTextJunction.java rename to src/main/java/com/avaje/ebeaninternal/api/SpiJunction.java index 7d3e1c086..e14da700e 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiTextJunction.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiJunction.java @@ -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 extends TextJunction { +public interface SpiJunction extends Junction { /** - * Write the junction expression to the query context. + * Write the Junction taking into account it is implied. */ void writeDocQueryJunction(DocQueryContext context) throws IOException; - } diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiTextExpressionList.java b/src/main/java/com/avaje/ebeaninternal/api/SpiTextExpressionList.java deleted file mode 100644 index 2c958e06e..000000000 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiTextExpressionList.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.avaje.ebeaninternal.api; - -import com.avaje.ebean.TextExpressionList; - -/** - * SPI extensions to Full text expression list. - */ -public interface SpiTextExpressionList extends TextExpressionList { - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java index 9f9b04ae4..78535986c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/AbstractTextExpression.java @@ -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; } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DTextJunction.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DTextJunction.java deleted file mode 100644 index 60ec67bb7..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DTextJunction.java +++ /dev/null @@ -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 extends JunctionExpression implements SpiTextJunction { - - private final TextJunction.Type type; - - DTextJunction(Query query, TextExpressionList parent, TextJunction.Type type) { - super(query, parent); - this.type = type; - } - - @Override - public void writeDocQueryJunction(DocQueryContext context) throws IOException { - context.startBoolGroupList(type); - List 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 match(String propertyName, String search) { - return match(propertyName, search, null); - } - - @Override - public TextExpressionList match(String propertyName, String search, Match options) { - return exprList.match(propertyName, search, options); - } - - @Override - public TextExpressionList multiMatch(String query, String... properties) { - return exprList.multiMatch(query, properties); - } - - @Override - public TextExpressionList multiMatch(String query, MultiMatch options) { - return exprList.multiMatch(query, options); - } - - @Override - public TextExpressionList textSimple(String search, TextSimple options) { - return exprList.textSimple(search, options); - } - - @Override - public TextExpressionList textQueryString(String search, TextQueryString options) { - return exprList.textQueryString(search, options); - } - - @Override - public TextExpressionList textCommonTerms(String search, TextCommonTerms options) { - return exprList.textCommonTerms(search, options); - } - - @Override - public TextJunction must() { - return exprList.must(); - } - - @Override - public TextJunction should() { - return exprList.should(); - } - - @Override - public TextJunction mustNot() { - return exprList.mustNot(); - } - - @Override - public TextExpressionList endMust() { - return endTextJunction(); - } - - @Override - public TextExpressionList endShould() { - return endTextJunction(); - } - - @Override - public TextExpressionList endMustNot() { - return endTextJunction(); - } - - private TextExpressionList endTextJunction() { - return exprList.endTextJunction(); - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionFactory.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionFactory.java index c57c9c9dd..fa7323d49 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionFactory.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionFactory.java @@ -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 Junction conjunction(Query query) { - return new JunctionExpression.Conjunction(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 Junction disjunction(Query query) { - return new JunctionExpression.Disjunction(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 Junction conjunction(Query query, ExpressionList parent) { - return new JunctionExpression.Conjunction(query, parent); } @@ -462,7 +457,6 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { * Return a list of expressions that will be joined by OR's. */ public Junction disjunction(Query query, ExpressionList parent) { - return new JunctionExpression.Disjunction(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 TextJunction textJunction(Query query, TextExpressionList parent, TextJunction.Type type) { - return new DTextJunction(query, parent, type); + public Junction textJunction(Query query, ExpressionList parent, Junction.Type type) { + return new JunctionExpression.TextJunction(query, parent, type); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index 2acb66fc8..00d62e2c8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -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 implements SpiExpressionList, SpiTextExpressionList { +public class DefaultExpressionList implements SpiExpressionList { protected final List list; protected final Query query; - protected final TextExpressionList parentExprList; + protected final ExpressionList parentExprList; protected transient ExpressionFactory expr; @@ -54,19 +53,19 @@ public class DefaultExpressionList implements SpiExpressionList, SpiTextEx this(query, query.getExpressionFactory(), null, new ArrayList(), true); } - public DefaultExpressionList(Query query, TextExpressionList parentExprList) { + public DefaultExpressionList(Query query, ExpressionList parentExprList) { this(query, query.getExpressionFactory(), parentExprList); } - public DefaultExpressionList(Query query, ExpressionFactory expr, TextExpressionList parentExprList) { + public DefaultExpressionList(Query query, ExpressionFactory expr, ExpressionList parentExprList) { this(query, expr, parentExprList, new ArrayList()); } - protected DefaultExpressionList(Query query, ExpressionFactory expr, TextExpressionList parentExprList, List list) { + protected DefaultExpressionList(Query query, ExpressionFactory expr, ExpressionList parentExprList, List list) { this(query, expr, parentExprList, list, false); } - private DefaultExpressionList(Query query, ExpressionFactory expr, TextExpressionList parentExprList, List list, boolean textRoot) { + private DefaultExpressionList(Query query, ExpressionFactory expr, ExpressionList parentExprList, List list, boolean textRoot) { this.textRoot = textRoot; this.list = list; this.query = query; @@ -104,20 +103,20 @@ public class DefaultExpressionList implements SpiExpressionList, 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 implements SpiExpressionList, SpiTextEx return parentExprList == null ? this : parentExprList; } - protected TextExpressionList endTextJunction() { + protected ExpressionList endTextJunction() { return parentExprList == null ? this : parentExprList; } @@ -647,8 +646,8 @@ public class DefaultExpressionList implements SpiExpressionList, SpiTextEx return this; } - public TextJunction textJunction(TextJunction.Type type) { - TextJunction junction = expr.textJunction(query, this, type); + public Junction textJunction(Junction.Type type) { + Junction junction = expr.textJunction(query, this, type); add(junction); return junction; } @@ -858,72 +857,77 @@ public class DefaultExpressionList implements SpiExpressionList, SpiTextEx } @Override - public TextExpressionList match(String propertyName, String search) { + public ExpressionList match(String propertyName, String search) { return match(propertyName, search, null); } @Override - public TextExpressionList match(String propertyName, String search, Match options) { + public ExpressionList match(String propertyName, String search, Match options) { add(expr.textMatch(propertyName, search, options)); + setUseDocStore(true); return this; } @Override - public TextExpressionList multiMatch(String query, String... fields) { - return multiMatch(query, new MultiMatch().fields(fields)); + public ExpressionList multiMatch(String query, String... fields) { + return multiMatch(query, MultiMatch.fields(fields)); } @Override - public TextExpressionList multiMatch(String query, MultiMatch options) { + public ExpressionList multiMatch(String query, MultiMatch options) { + setUseDocStore(true); add(expr.textMultiMatch(query, options)); return this; } @Override - public TextExpressionList textSimple(String search, TextSimple options) { + public ExpressionList textSimple(String search, TextSimple options) { + setUseDocStore(true); add(expr.textSimple(search, options)); return this; } @Override - public TextExpressionList textQueryString(String search, TextQueryString options) { + public ExpressionList textQueryString(String search, TextQueryString options) { + setUseDocStore(true); add(expr.textQueryString(search, options)); return this; } @Override - public TextExpressionList textCommonTerms(String search, TextCommonTerms options) { + public ExpressionList textCommonTerms(String search, TextCommonTerms options) { + setUseDocStore(true); add(expr.textCommonTerms(search, options)); return this; } @Override - public TextJunction must() { - return textJunction(TextJunction.Type.MUST); + public Junction must() { + return textJunction(Junction.Type.MUST); } @Override - public TextJunction should() { - return textJunction(TextJunction.Type.SHOULD); + public Junction should() { + return textJunction(Junction.Type.SHOULD); } @Override - public TextJunction mustNot() { - return textJunction(TextJunction.Type.MUST_NOT); + public Junction mustNot() { + return textJunction(Junction.Type.MUST_NOT); } @Override - public TextExpressionList endMust() { + public ExpressionList endMust() { return endTextJunction(); } @Override - public TextExpressionList endShould() { + public ExpressionList endShould() { return endTextJunction(); } @Override - public TextExpressionList endMustNot() { + public ExpressionList endMustNot() { return endTextJunction(); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DocQueryContext.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DocQueryContext.java index b289c6768..517bdfa8f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DocQueryContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DocQueryContext.java @@ -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. diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 38a2927e8..7519b25c0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -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 implements Junction, SpiExpression, ExpressionList { +abstract class JunctionExpression implements SpiJunction, SpiExpression, ExpressionList { - static final String OR = " or "; + static class TextJunction extends JunctionExpression { - static final String AND = " and "; + TextJunction(Query query, ExpressionList parent, TextJunction.Type type) { + super(type, query, parent); + } + TextJunction(TextJunction.Type type, DefaultExpressionList expressionList) { + super(type, expressionList); + } + @Override + public SpiExpression copyForPlanKey() { + return new TextJunction(type, exprList.copyForPlanKey()); + } + } static class Conjunction extends JunctionExpression { Conjunction(Query query, ExpressionList parent) { - super(false, AND, query, parent); + super(Type.AND, query, parent); } Conjunction(DefaultExpressionList expressionList) { - super(false, AND, expressionList); + super(Type.AND, expressionList); } @Override public SpiExpression copyForPlanKey() { @@ -43,11 +59,11 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr static class Disjunction extends JunctionExpression { Disjunction(Query query, ExpressionList parent) { - super(true, OR, query, parent); + super(Type.OR, query, parent); } Disjunction(DefaultExpressionList expressionList) { - super(true, OR, expressionList); + super(Type.OR, expressionList); } @Override @@ -58,37 +74,24 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr protected final DefaultExpressionList 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 query, TextExpressionList parent) { - this.disjunction = true; - this.joinType = OR; + JunctionExpression(Junction.Type type, Query query, ExpressionList parent) { + this.type = type; this.exprList = new DefaultExpressionList(query, parent); } - JunctionExpression(boolean disjunction, String joinType, Query query, ExpressionList parent) { - this.disjunction = disjunction; - this.joinType = joinType; - this.exprList = new DefaultExpressionList(query, (TextExpressionList)parent); - } - /** * Construct for copyForPlanKey. */ - JunctionExpression(boolean disjunction, String joinType, DefaultExpressionList exprList) { - this.disjunction = disjunction; - this.joinType = joinType; + JunctionExpression(Junction.Type type, DefaultExpressionList exprList) { + this.type = type; this.exprList = exprList; } @Override public void writeDocQuery(DocQueryContext context) throws IOException { - context.startBool(!disjunction); + context.startBool(type == Type.AND); List list = exprList.internalList(); for (int i = 0; i < list.size(); i++) { list.get(i).writeDocQuery(context); @@ -96,6 +99,16 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr context.endBool(); } + @Override + public void writeDocQueryJunction(DocQueryContext context) throws IOException { + context.startBoolGroupList(type); + List 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 implements Junction, 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 implements Junction, 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 implements Junction, 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 implements Junction, SpiExpression, Expr */ @Override public void queryPlanHash(HashQueryPlanBuilder builder) { - builder.add(JunctionExpression.class).add(joinType); + builder.add(JunctionExpression.class).add(type); List list = exprList.internalList(); for (int i = 0; i < list.size(); i++) { list.get(i).queryPlanHash(builder); @@ -204,15 +217,82 @@ abstract class JunctionExpression implements Junction, 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 match(String propertyName, String search) { + return match(propertyName, search, null); + } + + @Override + public ExpressionList match(String propertyName, String search, Match options) { + return exprList.match(propertyName, search, options); + } + + @Override + public ExpressionList multiMatch(String query, String... properties) { + return exprList.multiMatch(query, properties); + } + + @Override + public ExpressionList multiMatch(String query, MultiMatch options) { + return exprList.multiMatch(query, options); + } + + @Override + public ExpressionList textSimple(String search, TextSimple options) { + return exprList.textSimple(search, options); + } + + @Override + public ExpressionList textQueryString(String search, TextQueryString options) { + return exprList.textQueryString(search, options); + } + + @Override + public ExpressionList textCommonTerms(String search, TextCommonTerms options) { + return exprList.textCommonTerms(search, options); + } + + @Override + public Junction must() { + return exprList.must(); + } + + @Override + public Junction should() { + return exprList.should(); + } + + @Override + public Junction mustNot() { + return exprList.mustNot(); + } + + @Override + public ExpressionList endMust() { + return endTextJunction(); + } + + @Override + public ExpressionList endShould() { + return endTextJunction(); + } + + @Override + public ExpressionList endMustNot() { + return endTextJunction(); + } + + private ExpressionList endTextJunction() { + return exprList.endTextJunction(); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 39a7cacdc..b646f4d56 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1316,7 +1316,7 @@ public class DefaultOrmQuery implements SpiQuery { } @Override - public TextExpressionList text() { + public ExpressionList text() { if (textExpressions == null) { useDocStore = true; textExpressions = new DefaultExpressionList(this); diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 3c6422264..e7e24a770 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -77,9 +77,9 @@ - - - + + +