mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#606 - Add not() as a junction expression (like and() and or()) to the query criteria API
This commit is contained in:
@@ -357,6 +357,6 @@ public interface ExpressionFactory {
|
||||
* This is doc store Elastic only.
|
||||
* </p>
|
||||
*/
|
||||
<T> Junction<T> textJunction(Query<T> query, ExpressionList<T> parent, Junction.Type type);
|
||||
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
}
|
||||
|
||||
@@ -900,6 +900,11 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Junction<T> or();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be wrapped by NOT.
|
||||
*/
|
||||
Junction<T> not();
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
@@ -910,15 +915,6 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Junction<T> disjunction();
|
||||
|
||||
/**
|
||||
* End a Conjunction or Disjunction returning the parent expression list.
|
||||
* <p>
|
||||
* Alternatively you can always use where() to return the top level expression
|
||||
* list.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> endJunction();
|
||||
|
||||
/**
|
||||
* Start a list of expressions that will be joined by MUST.
|
||||
*/
|
||||
@@ -934,6 +930,30 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Junction<T> mustNot();
|
||||
|
||||
/**
|
||||
* End a Conjunction or Disjunction returning the parent expression list.
|
||||
* <p>
|
||||
* Alternatively you can always use where() to return the top level expression
|
||||
* list.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<T> endJunction();
|
||||
|
||||
/**
|
||||
* End the list of AND expressions.
|
||||
*/
|
||||
ExpressionList<T> endAnd();
|
||||
|
||||
/**
|
||||
* End the list of OR expressions.
|
||||
*/
|
||||
ExpressionList<T> endOr();
|
||||
|
||||
/**
|
||||
* End the list of NOT expressions.
|
||||
*/
|
||||
ExpressionList<T> endNot();
|
||||
|
||||
/**
|
||||
* End the list of MUST expressions.
|
||||
*/
|
||||
|
||||
@@ -10,68 +10,68 @@ package com.avaje.ebean;
|
||||
* Note: where() always takes you to the top level WHERE expression list.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where().disjunction()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
*
|
||||
* // where() returns us to the top level expression list
|
||||
* .where().gt("id", 10);
|
||||
* .where().gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note: endJunction() takes you to the parent expression list
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* .where().disjunction()
|
||||
* .like("name", "Rob%")
|
||||
* .eq("status", Status.NEW)
|
||||
* .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);
|
||||
* .gt("id", 10);
|
||||
*
|
||||
* // read as...
|
||||
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example of a nested disjunction.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Query<Customer> q =
|
||||
* <pre>{@code
|
||||
* Query<Customer> q =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .disjunction()
|
||||
* .conjunction()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .or()
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .conjunction()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .order().asc("name");
|
||||
* .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 > ? )
|
||||
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id > ? )
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
|
||||
@@ -83,32 +83,39 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
/**
|
||||
* AND group.
|
||||
*/
|
||||
AND(" and "),
|
||||
AND(" and ", ""),
|
||||
|
||||
/**
|
||||
* OR group.
|
||||
*/
|
||||
OR(" or "),
|
||||
OR(" or ", ""),
|
||||
|
||||
/**
|
||||
* NOT group.
|
||||
*/
|
||||
NOT(" and ", "not "),
|
||||
|
||||
/**
|
||||
* Text search AND group.
|
||||
*/
|
||||
MUST("must"),
|
||||
MUST("must", ""),
|
||||
|
||||
/**
|
||||
* Text search NOT group.
|
||||
*/
|
||||
MUST_NOT("must_not"),
|
||||
MUST_NOT("must_not", ""),
|
||||
|
||||
/**
|
||||
* Text search OR group.
|
||||
*/
|
||||
SHOULD("should");
|
||||
SHOULD("should", "");
|
||||
|
||||
String prefix;
|
||||
String literal;
|
||||
|
||||
Type(String literal) {
|
||||
Type(String literal, String prefix) {
|
||||
this.literal = literal;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,6 +124,13 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
public String literal() {
|
||||
return literal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prefix value for this type.
|
||||
*/
|
||||
public String prefix() {
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-6
@@ -436,35 +436,42 @@ 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());
|
||||
return new JunctionExpression<T>(Junction.Type.AND, query, query.where());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
return new JunctionExpression<T>(Junction.Type.OR, query, query.where());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
return new JunctionExpression<T>(Junction.Type.AND, query, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
return new JunctionExpression<T>(Junction.Type.OR, query, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that are wrapped by NOT.
|
||||
*/
|
||||
public <T> Junction<T> junction(Junction.Type type, Query<T> query) {
|
||||
return new JunctionExpression<T>(type, query, query.where());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a Full text junction (Must, Must Not or Should).
|
||||
*/
|
||||
@Override
|
||||
public <T> Junction<T> textJunction(Query<T> query, ExpressionList<T> parent, Junction.Type type) {
|
||||
return new JunctionExpression.TextJunction<T>(query, parent, type);
|
||||
public <T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent) {
|
||||
return new JunctionExpression<T>(type, query, parent);
|
||||
}
|
||||
}
|
||||
|
||||
+57
-45
@@ -202,15 +202,6 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endJunction() {
|
||||
return parentExprList == null ? this : parentExprList;
|
||||
}
|
||||
|
||||
protected ExpressionList<T> endTextJunction() {
|
||||
return parentExprList == null ? this : parentExprList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> query() {
|
||||
return query;
|
||||
@@ -646,42 +637,12 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Junction<T> textJunction(Junction.Type type) {
|
||||
Junction<T> junction = expr.textJunction(query, this, type);
|
||||
add(junction);
|
||||
return junction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> and() {
|
||||
return conjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> or() {
|
||||
return disjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> conjunction() {
|
||||
Junction<T> conjunction = expr.conjunction(query, this);
|
||||
add(conjunction);
|
||||
return conjunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> contains(String propertyName, String value) {
|
||||
add(expr.contains(propertyName, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> disjunction() {
|
||||
Junction<T> disjunction = expr.disjunction(query, this);
|
||||
add(disjunction);
|
||||
return disjunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endsWith(String propertyName, String value) {
|
||||
add(expr.endsWith(propertyName, value));
|
||||
@@ -911,33 +872,84 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
private Junction<T> junction(Junction.Type type) {
|
||||
Junction<T> junction = expr.junction(type, query, this);
|
||||
add(junction);
|
||||
return junction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endJunction() {
|
||||
return parentExprList == null ? this : parentExprList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> and() {
|
||||
return conjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> or() {
|
||||
return disjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> not() {
|
||||
return junction(Junction.Type.NOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> conjunction() {
|
||||
return junction(Junction.Type.AND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> disjunction() {
|
||||
return junction(Junction.Type.OR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> must() {
|
||||
return textJunction(Junction.Type.MUST);
|
||||
return junction(Junction.Type.MUST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> should() {
|
||||
return textJunction(Junction.Type.SHOULD);
|
||||
return junction(Junction.Type.SHOULD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> mustNot() {
|
||||
return textJunction(Junction.Type.MUST_NOT);
|
||||
return junction(Junction.Type.MUST_NOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endAnd() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endOr() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endNot() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endMust() {
|
||||
return endTextJunction();
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endShould() {
|
||||
return endTextJunction();
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endMustNot() {
|
||||
return endTextJunction();
|
||||
return endJunction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
package com.avaje.ebeaninternal.server.expression;
|
||||
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.Expression;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.FetchPath;
|
||||
import com.avaje.ebean.FutureIds;
|
||||
import com.avaje.ebean.FutureList;
|
||||
import com.avaje.ebean.FutureRowCount;
|
||||
import com.avaje.ebean.Junction;
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.PagedList;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.search.Match;
|
||||
import com.avaje.ebean.search.MultiMatch;
|
||||
@@ -25,52 +38,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Junction implementation.
|
||||
*/
|
||||
abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> {
|
||||
|
||||
static class TextJunction<T> extends JunctionExpression<T> {
|
||||
|
||||
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(Type.AND, query, parent);
|
||||
}
|
||||
|
||||
Conjunction(DefaultExpressionList<T> expressionList) {
|
||||
super(Type.AND, expressionList);
|
||||
}
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new Conjunction<T>(exprList.copyForPlanKey());
|
||||
}
|
||||
}
|
||||
|
||||
static class Disjunction<T> extends JunctionExpression<T> {
|
||||
|
||||
Disjunction(Query<T> query, ExpressionList<T> parent) {
|
||||
super(Type.OR, query, parent);
|
||||
}
|
||||
|
||||
Disjunction(DefaultExpressionList<T> expressionList) {
|
||||
super(Type.OR, expressionList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new Disjunction<T>(exprList.copyForPlanKey());
|
||||
}
|
||||
}
|
||||
class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> {
|
||||
|
||||
protected final DefaultExpressionList<T> exprList;
|
||||
|
||||
@@ -89,6 +57,10 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
this.exprList = exprList;
|
||||
}
|
||||
|
||||
public SpiExpression copyForPlanKey() {
|
||||
return new JunctionExpression<T>(type, exprList.copyForPlanKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDocQuery(DocQueryContext context) throws IOException {
|
||||
context.startBool(type == Type.AND);
|
||||
@@ -151,7 +123,6 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
list.get(i).addBindValues(request);
|
||||
}
|
||||
@@ -163,8 +134,8 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
request.append(type.prefix());
|
||||
request.append("(");
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
SpiExpression item = list.get(i);
|
||||
if (i > 0) {
|
||||
@@ -172,7 +143,6 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
}
|
||||
item.addSql(request);
|
||||
}
|
||||
|
||||
request.append(") ");
|
||||
}
|
||||
}
|
||||
@@ -200,12 +170,10 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
@Override
|
||||
public int queryBindHash() {
|
||||
int hc = JunctionExpression.class.getName().hashCode();
|
||||
|
||||
List<SpiExpression> list = exprList.internalList();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
hc = hc * 31 + list.get(i).queryBindHash();
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
@@ -261,44 +229,6 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
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
|
||||
public ExpressionList<T> endJunction() {
|
||||
return exprList.endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> allEq(Map<String, Object> propertyMap) {
|
||||
@@ -320,31 +250,11 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
return exprList.betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> and() {
|
||||
return conjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> or() {
|
||||
return disjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> conjunction() {
|
||||
return exprList.conjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> contains(String propertyName, String value) {
|
||||
return exprList.contains(propertyName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> disjunction() {
|
||||
return exprList.disjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endsWith(String propertyName, String value) {
|
||||
return exprList.endsWith(propertyName, value);
|
||||
@@ -787,4 +697,79 @@ abstract class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, E
|
||||
return exprList.where();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> and() {
|
||||
return conjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> or() {
|
||||
return disjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> not() {
|
||||
return exprList.not();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> conjunction() {
|
||||
return exprList.conjunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Junction<T> disjunction() {
|
||||
return exprList.disjunction();
|
||||
}
|
||||
|
||||
@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> endJunction() {
|
||||
return exprList.endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endAnd() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endOr() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endNot() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endMust() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endShould() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> endMustNot() {
|
||||
return endJunction();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user