endNot();
+
/**
* End the list of MUST expressions.
*/
diff --git a/src/main/java/com/avaje/ebean/Junction.java b/src/main/java/com/avaje/ebean/Junction.java
index 36a130ee7..06af1586b 100644
--- a/src/main/java/com/avaje/ebean/Junction.java
+++ b/src/main/java/com/avaje/ebean/Junction.java
@@ -10,68 +10,68 @@ package com.avaje.ebean;
* Note: where() always takes you to the top level WHERE expression list.
*
*
- *
+ * {@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) )
- *
+ * }
*
*
* Note: endJunction() takes you to the parent expression list
*
*
- *
+ * {@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) )
- *
+ * }
*
*
* Example of a nested disjunction.
*
*
- *
- * Query<Customer> q =
+ * {@code
+ * Query 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 > ? )
*
- *
+ * }
*/
public interface Junction extends Expression, ExpressionList {
@@ -83,32 +83,39 @@ public interface Junction extends Expression, ExpressionList {
/**
* 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 extends Expression, ExpressionList {
public String literal() {
return literal;
}
+
+ /**
+ * Return the prefix value for this type.
+ */
+ public String prefix() {
+ return prefix;
+ }
}
}
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 fa7323d49..c74f9b339 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionFactory.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionFactory.java
@@ -436,35 +436,42 @@ 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());
+ return new JunctionExpression(Junction.Type.AND, query, query.where());
}
/**
* Return a list of expressions that will be joined by OR's.
*/
public Junction disjunction(Query query) {
- return new JunctionExpression.Disjunction(query, query.where());
+ return new JunctionExpression(Junction.Type.OR, query, query.where());
}
/**
* 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);
+ return new JunctionExpression(Junction.Type.AND, query, parent);
}
/**
* 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);
+ return new JunctionExpression(Junction.Type.OR, query, parent);
+ }
+
+ /**
+ * Return a list of expressions that are wrapped by NOT.
+ */
+ public Junction junction(Junction.Type type, Query query) {
+ return new JunctionExpression(type, query, query.where());
}
/**
* Create and return a Full text junction (Must, Must Not or Should).
*/
@Override
- public Junction textJunction(Query query, ExpressionList parent, Junction.Type type) {
- return new JunctionExpression.TextJunction(query, parent, type);
+ public Junction junction(Junction.Type type, Query query, ExpressionList parent) {
+ return new JunctionExpression(type, query, parent);
}
}
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 d0dfb166d..d8d4332e1 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java
@@ -202,15 +202,6 @@ public class DefaultExpressionList implements SpiExpressionList {
}
}
- @Override
- public ExpressionList endJunction() {
- return parentExprList == null ? this : parentExprList;
- }
-
- protected ExpressionList endTextJunction() {
- return parentExprList == null ? this : parentExprList;
- }
-
@Override
public Query query() {
return query;
@@ -646,42 +637,12 @@ public class DefaultExpressionList implements SpiExpressionList {
return this;
}
- public Junction textJunction(Junction.Type type) {
- Junction junction = expr.textJunction(query, this, type);
- add(junction);
- return junction;
- }
-
- @Override
- public Junction and() {
- return conjunction();
- }
-
- @Override
- public Junction or() {
- return disjunction();
- }
-
- @Override
- public Junction conjunction() {
- Junction conjunction = expr.conjunction(query, this);
- add(conjunction);
- return conjunction;
- }
-
@Override
public ExpressionList contains(String propertyName, String value) {
add(expr.contains(propertyName, value));
return this;
}
- @Override
- public Junction disjunction() {
- Junction disjunction = expr.disjunction(query, this);
- add(disjunction);
- return disjunction;
- }
-
@Override
public ExpressionList endsWith(String propertyName, String value) {
add(expr.endsWith(propertyName, value));
@@ -911,33 +872,84 @@ public class DefaultExpressionList implements SpiExpressionList {
return this;
}
+ private Junction junction(Junction.Type type) {
+ Junction junction = expr.junction(type, query, this);
+ add(junction);
+ return junction;
+ }
+
+ @Override
+ public ExpressionList endJunction() {
+ return parentExprList == null ? this : parentExprList;
+ }
+
+ @Override
+ public Junction and() {
+ return conjunction();
+ }
+
+ @Override
+ public Junction or() {
+ return disjunction();
+ }
+
+ @Override
+ public Junction not() {
+ return junction(Junction.Type.NOT);
+ }
+
+ @Override
+ public Junction conjunction() {
+ return junction(Junction.Type.AND);
+ }
+
+ @Override
+ public Junction disjunction() {
+ return junction(Junction.Type.OR);
+ }
+
@Override
public Junction must() {
- return textJunction(Junction.Type.MUST);
+ return junction(Junction.Type.MUST);
}
@Override
public Junction should() {
- return textJunction(Junction.Type.SHOULD);
+ return junction(Junction.Type.SHOULD);
}
@Override
public Junction mustNot() {
- return textJunction(Junction.Type.MUST_NOT);
+ return junction(Junction.Type.MUST_NOT);
+ }
+
+ @Override
+ public ExpressionList endAnd() {
+ return endJunction();
+ }
+
+ @Override
+ public ExpressionList endOr() {
+ return endJunction();
+ }
+
+ @Override
+ public ExpressionList endNot() {
+ return endJunction();
}
@Override
public ExpressionList endMust() {
- return endTextJunction();
+ return endJunction();
}
@Override
public ExpressionList endShould() {
- return endTextJunction();
+ return endJunction();
}
@Override
public ExpressionList endMustNot() {
- return endTextJunction();
+ return endJunction();
}
}
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 64708122c..beca6b9e1 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
@@ -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 implements SpiJunction, SpiExpression, ExpressionList {
-
- static class TextJunction extends JunctionExpression {
-
- 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(Type.AND, query, parent);
- }
-
- Conjunction(DefaultExpressionList expressionList) {
- super(Type.AND, expressionList);
- }
- @Override
- public SpiExpression copyForPlanKey() {
- return new Conjunction(exprList.copyForPlanKey());
- }
- }
-
- static class Disjunction extends JunctionExpression {
-
- Disjunction(Query query, ExpressionList parent) {
- super(Type.OR, query, parent);
- }
-
- Disjunction(DefaultExpressionList expressionList) {
- super(Type.OR, expressionList);
- }
-
- @Override
- public SpiExpression copyForPlanKey() {
- return new Disjunction(exprList.copyForPlanKey());
- }
- }
+class JunctionExpression implements SpiJunction, SpiExpression, ExpressionList {
protected final DefaultExpressionList exprList;
@@ -89,6 +57,10 @@ abstract class JunctionExpression implements SpiJunction, SpiExpression, E
this.exprList = exprList;
}
+ public SpiExpression copyForPlanKey() {
+ return new JunctionExpression(type, exprList.copyForPlanKey());
+ }
+
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.startBool(type == Type.AND);
@@ -151,7 +123,6 @@ abstract class JunctionExpression implements SpiJunction, SpiExpression, E
public void addBindValues(SpiExpressionRequest request) {
List list = exprList.internalList();
-
for (int i = 0; i < list.size(); i++) {
list.get(i).addBindValues(request);
}
@@ -163,8 +134,8 @@ abstract class JunctionExpression implements SpiJunction, SpiExpression, E
List 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 implements SpiJunction, SpiExpression, E
}
item.addSql(request);
}
-
request.append(") ");
}
}
@@ -200,12 +170,10 @@ abstract class JunctionExpression implements SpiJunction, SpiExpression, E
@Override
public int queryBindHash() {
int hc = JunctionExpression.class.getName().hashCode();
-
List 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 implements SpiJunction, SpiExpression, E
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
- public ExpressionList endJunction() {
- return exprList.endJunction();
- }
@Override
public ExpressionList allEq(Map propertyMap) {
@@ -320,31 +250,11 @@ abstract class JunctionExpression implements SpiJunction, SpiExpression, E
return exprList.betweenProperties(lowProperty, highProperty, value);
}
- @Override
- public Junction and() {
- return conjunction();
- }
-
- @Override
- public Junction or() {
- return disjunction();
- }
-
- @Override
- public Junction conjunction() {
- return exprList.conjunction();
- }
-
@Override
public ExpressionList contains(String propertyName, String value) {
return exprList.contains(propertyName, value);
}
- @Override
- public Junction disjunction() {
- return exprList.disjunction();
- }
-
@Override
public ExpressionList endsWith(String propertyName, String value) {
return exprList.endsWith(propertyName, value);
@@ -787,4 +697,79 @@ abstract class JunctionExpression implements SpiJunction, SpiExpression, E
return exprList.where();
}
+ @Override
+ public Junction and() {
+ return conjunction();
+ }
+
+ @Override
+ public Junction or() {
+ return disjunction();
+ }
+
+ @Override
+ public Junction not() {
+ return exprList.not();
+ }
+
+ @Override
+ public Junction conjunction() {
+ return exprList.conjunction();
+ }
+
+ @Override
+ public Junction disjunction() {
+ return exprList.disjunction();
+ }
+
+ @Override
+ public Junction must() {
+ return exprList.must();
+ }
+
+ @Override
+ public Junction should() {
+ return exprList.should();
+ }
+
+ @Override
+ public Junction mustNot() {
+ return exprList.mustNot();
+ }
+
+ @Override
+ public ExpressionList endJunction() {
+ return exprList.endJunction();
+ }
+
+ @Override
+ public ExpressionList endAnd() {
+ return endJunction();
+ }
+
+ @Override
+ public ExpressionList endOr() {
+ return endJunction();
+ }
+
+ @Override
+ public ExpressionList endNot() {
+ return endJunction();
+ }
+
+ @Override
+ public ExpressionList endMust() {
+ return endJunction();
+ }
+
+ @Override
+ public ExpressionList endShould() {
+ return endJunction();
+ }
+
+ @Override
+ public ExpressionList endMustNot() {
+ return endJunction();
+ }
+
}
diff --git a/src/test/java/com/avaje/ebeaninternal/server/expression/JunctionExpressionTest.java b/src/test/java/com/avaje/ebeaninternal/server/expression/JunctionExpressionTest.java
index a4bd1c166..26610a0c4 100644
--- a/src/test/java/com/avaje/ebeaninternal/server/expression/JunctionExpressionTest.java
+++ b/src/test/java/com/avaje/ebeaninternal/server/expression/JunctionExpressionTest.java
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Expr;
import com.avaje.ebean.Expression;
+import com.avaje.ebean.Junction;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
@@ -23,11 +24,11 @@ public class JunctionExpressionTest {
}
JunctionExpression and(DefaultExpressionList list) {
- return new JunctionExpression.Conjunction(list);
+ return new JunctionExpression(Junction.Type.AND, list);
}
JunctionExpression or(DefaultExpressionList list) {
- return new JunctionExpression.Disjunction(list);
+ return new JunctionExpression(Junction.Type.OR, list);
}
@Test
diff --git a/src/test/java/com/avaje/tests/query/TestExprNestedDisjunction.java b/src/test/java/com/avaje/tests/query/TestExprNestedDisjunction.java
index 3e2bbb697..3f178646d 100644
--- a/src/test/java/com/avaje/tests/query/TestExprNestedDisjunction.java
+++ b/src/test/java/com/avaje/tests/query/TestExprNestedDisjunction.java
@@ -9,6 +9,8 @@ import com.avaje.ebean.Query;
import com.avaje.tests.model.basic.Customer;
import com.avaje.tests.model.basic.ResetBasicData;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestExprNestedDisjunction extends BaseTestCase {
@Test
@@ -42,9 +44,11 @@ public class TestExprNestedDisjunction extends BaseTestCase {
.where()
.or()
.and()
- .startsWith("name", "r").eq("anniversary", onAfter).endJunction()
- .and().eq("status", Customer.Status.ACTIVE).gt("id", 0).endJunction().orderBy()
- .asc("name");
+ .startsWith("name", "r").eq("anniversary", onAfter).endAnd()
+ .and()
+ .eq("status", Customer.Status.ACTIVE).gt("id", 0).endAnd()
+ .endOr()
+ .orderBy().asc("name");
q.findList();
String s = q.getGeneratedSql();
@@ -52,4 +56,48 @@ public class TestExprNestedDisjunction extends BaseTestCase {
Assert.assertTrue(s.contains("(t0.name like ? "));
Assert.assertTrue(s.contains(" and t0.anniversary = ? ) or (t0.status = ? and t0.id > ? )"));
}
+
+ @Test
+ public void test_not() {
+
+ ResetBasicData.reset();
+
+ java.sql.Date onAfter = java.sql.Date.valueOf("2009-08-31");
+
+ Query q = Ebean.find(Customer.class)
+ .where()
+ .not()
+ .gt("id", 1)
+ .eq("anniversary", onAfter)
+ .endNot()
+ .orderBy().asc("name");
+
+ q.findList();
+ String s = q.getGeneratedSql();
+
+ assertThat(s).contains("where not (t0.id > ? and t0.anniversary = ? ) order by t0.name");
+ }
+
+ @Test
+ public void test_not_nested() {
+
+ ResetBasicData.reset();
+
+ java.sql.Date onAfter = java.sql.Date.valueOf("2009-08-31");
+
+ Query q = Ebean.find(Customer.class)
+ .where()
+ .or()
+ .eq("status", Customer.Status.ACTIVE)
+ .not()
+ .gt("id", 1)
+ .eq("anniversary", onAfter)
+ //.endNot()
+ .orderBy().asc("name");
+
+ q.findList();
+ String s = q.getGeneratedSql();
+
+ assertThat(s).contains("where (t0.status = ? or not (t0.id > ? and t0.anniversary = ? ) )");
+ }
}