diff --git a/src/main/java/io/ebean/Expr.java b/src/main/java/io/ebean/Expr.java
index 0bf0ddc4d..3b6ec35b4 100644
--- a/src/main/java/io/ebean/Expr.java
+++ b/src/main/java/io/ebean/Expr.java
@@ -71,7 +71,6 @@ public class Expr {
*
*/
public static Expression inRange(String propertyName, Object value1, Object value2) {
-
return Ebean.getExpressionFactory().inRange(propertyName, value1, value2);
}
@@ -79,7 +78,6 @@ public class Expr {
* Between - property between the two given values.
*/
public static Expression between(String propertyName, Object value1, Object value2) {
-
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
}
@@ -87,7 +85,6 @@ public class Expr {
* Between - value between two given properties.
*/
public static Expression between(String lowProperty, String highProperty, Object value) {
-
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
}
diff --git a/src/main/java/io/ebean/ExpressionFactory.java b/src/main/java/io/ebean/ExpressionFactory.java
index e3455cc3f..873d82dd1 100644
--- a/src/main/java/io/ebean/ExpressionFactory.java
+++ b/src/main/java/io/ebean/ExpressionFactory.java
@@ -157,6 +157,25 @@ public interface ExpressionFactory {
*/
Expression inRange(String propertyName, Object value1, Object value2);
+ /**
+ * Value in Range between 2 properties.
+ *
+ * {@code
+ *
+ * .startDate.inRangeWith(endDate, now)
+ *
+ * // which equates to
+ * startDate <= now and (endDate > now or endDate is null)
+ *
+ * }
+ *
+ *
+ * This is a convenience expression combining a number of simple expressions.
+ * The most common use of this could be called "effective dating" where 2 date or
+ * timestamp columns represent the date range in which
+ */
+ Expression inRangeWith(String lowProperty, String highProperty, Object value);
+
/**
* Between - property between the two given values.
*/
@@ -167,6 +186,14 @@ public interface ExpressionFactory {
*/
Expression betweenProperties(String lowProperty, String highProperty, Object value);
+ /**
+ * Greater Than Or Null - property greater than the given value or null.
+ *
+ * A convenient expression combining GT and Is Null. Most often useful for range
+ * expressions where the top range value is nullable.
+ */
+ Expression gtOrNull(String propertyName, Object value);
+
/**
* Greater Than - property greater than the given value.
*/
@@ -178,6 +205,14 @@ public interface ExpressionFactory {
*/
Expression ge(String propertyName, Object value);
+ /**
+ * Less Than or Null - property less than the given value or null.
+ *
+ * A convenient expression combining LT and Is Null. Most often useful for range
+ * expressions where the bottom range value is nullable.
+ */
+ Expression ltOrNull(String propertyName, Object value);
+
/**
* Less Than - property less than the given value.
*/
diff --git a/src/main/java/io/ebean/ExpressionList.java b/src/main/java/io/ebean/ExpressionList.java
index 4e8bf5e62..9759a9028 100644
--- a/src/main/java/io/ebean/ExpressionList.java
+++ b/src/main/java/io/ebean/ExpressionList.java
@@ -802,6 +802,25 @@ public interface ExpressionList {
*/
ExpressionList ine(String propertyName, String value);
+ /**
+ * Value in Range between 2 properties.
+ *
+ * {@code
+ *
+ * .startDate.inRangeWith(endDate, now)
+ *
+ * // which equates to
+ * startDate <= now and (endDate > now or endDate is null)
+ *
+ * }
+ *
+ *
+ * This is a convenience expression combining a number of simple expressions.
+ * The most common use of this could be called "effective dating" where 2 date or
+ * timestamp columns represent the date range in which
+ */
+ ExpressionList inRangeWith(String lowProperty, String highProperty, Object value);
+
/**
* In Range - property >= value1 and property < value2.
*
@@ -825,6 +844,11 @@ public interface ExpressionList {
*/
ExpressionList gt(String propertyName, Object value);
+ /**
+ * Greater Than or Null - property greater than the given value or null.
+ */
+ ExpressionList gtOrNull(String propertyName, Object value);
+
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
@@ -836,6 +860,11 @@ public interface ExpressionList {
*/
ExpressionList lt(String propertyName, Object value);
+ /**
+ * Less Than or Null - property less than the given value or null.
+ */
+ ExpressionList ltOrNull(String propertyName, Object value);
+
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java
index d7a1d9e36..e952b63d4 100644
--- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java
+++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java
@@ -221,6 +221,11 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
return new InRangeExpression(propertyName, value1, value2);
}
+ @Override
+ public Expression inRangeWith(String lowProperty, String highProperty, Object value) {
+ return and(le(lowProperty, value), gtOrNull(highProperty, value));
+ }
+
/**
* Between - property between the two given values.
*/
@@ -245,6 +250,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
return new SimpleExpression(propertyName, Op.GT, value);
}
+ /**
+ * Greater Than or null - property greater than the given value or null.
+ */
+ @Override
+ public Expression gtOrNull(String propertyName, Object value) {
+ return or(gt(propertyName, value), isNull(propertyName));
+ }
+
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
@@ -254,6 +267,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
return new SimpleExpression(propertyName, Op.GT_EQ, value);
}
+ /**
+ * Less Than or null - property less than the given value or null.
+ */
+ @Override
+ public Expression ltOrNull(String propertyName, Object value) {
+ return or(lt(propertyName, value), isNull(propertyName));
+ }
+
/**
* Less Than - property less than the given value.
*/
diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
index 9f472b255..e0b6215d7 100644
--- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
+++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java
@@ -794,6 +794,12 @@ public class DefaultExpressionList implements SpiExpressionList {
return this;
}
+ @Override
+ public ExpressionList inRangeWith(String lowProperty, String highProperty, Object value) {
+ add(expr.inRangeWith(lowProperty, highProperty, value));
+ return this;
+ }
+
@Override
public ExpressionList inRange(String propertyName, Object value1, Object value2) {
add(expr.inRange(propertyName, value1, value2));
@@ -836,6 +842,12 @@ public class DefaultExpressionList implements SpiExpressionList {
return this;
}
+ @Override
+ public ExpressionList gtOrNull(String propertyName, Object value) {
+ add(expr.gtOrNull(propertyName, value));
+ return this;
+ }
+
@Override
public ExpressionList icontains(String propertyName, String value) {
add(expr.icontains(propertyName, value));
@@ -990,6 +1002,12 @@ public class DefaultExpressionList implements SpiExpressionList {
return this;
}
+ @Override
+ public ExpressionList ltOrNull(String propertyName, Object value) {
+ add(expr.ltOrNull(propertyName, value));
+ return this;
+ }
+
@Override
public ExpressionList not(Expression exp) {
add(expr.not(exp));
diff --git a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
index c1ed7b611..dc251f07c 100644
--- a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
+++ b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java
@@ -280,6 +280,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression
return exprList.and(expOne, expTwo);
}
+ @Override
+ public ExpressionList inRangeWith(String lowProperty, String highProperty, Object value) {
+ return exprList.inRangeWith(lowProperty, highProperty, value);
+ }
+
@Override
public ExpressionList inRange(String propertyName, Object value1, Object value2) {
return exprList.inRange(propertyName, value1, value2);
@@ -597,6 +602,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression
return exprList.gt(propertyName, value);
}
+ @Override
+ public ExpressionList gtOrNull(String propertyName, Object value) {
+ return exprList.gtOrNull(propertyName, value);
+ }
+
@Override
public ExpressionList having() {
throw new IllegalStateException("having() not allowed on Junction expression list");
@@ -732,6 +742,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression
return exprList.lt(propertyName, value);
}
+ @Override
+ public ExpressionList ltOrNull(String propertyName, Object value) {
+ return exprList.ltOrNull(propertyName, value);
+ }
+
@Override
public ExpressionList ne(String propertyName, Object value) {
return exprList.ne(propertyName, value);
diff --git a/src/test/java/org/tests/basic/TestQueryWhereInRange.java b/src/test/java/org/tests/basic/TestQueryWhereInRange.java
index 86de95624..e32831496 100644
--- a/src/test/java/org/tests/basic/TestQueryWhereInRange.java
+++ b/src/test/java/org/tests/basic/TestQueryWhereInRange.java
@@ -1,7 +1,7 @@
package org.tests.basic;
import io.ebean.BaseTestCase;
-import io.ebean.Ebean;
+import io.ebean.DB;
import io.ebean.Query;
import org.junit.Test;
import org.tests.model.basic.Order;
@@ -9,6 +9,8 @@ import org.tests.model.basic.ResetBasicData;
import java.time.LocalDate;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class TestQueryWhereInRange extends BaseTestCase {
@Test
@@ -18,14 +20,61 @@ public class TestQueryWhereInRange extends BaseTestCase {
LocalDate today = LocalDate.now();
- Query query= Ebean.find(Order.class)
+ Query query = DB.find(Order.class)
.where().inRange("orderDate", today.minusDays(7), today)
.isNotNull("id")
.query();
query.findList();
- sqlOf(query).contains("(order_date >= ? and order_date < ?)");
+ assertThat(sqlOf(query)).contains("where (t0.order_date >= ? and t0.order_date < ?) and ");
+ }
+ @Test
+ public void gtOrNull() {
+
+ ResetBasicData.reset();
+
+ LocalDate today = LocalDate.now();
+
+ Query query = DB.find(Order.class)
+ .where().gtOrNull("orderDate", today)
+ .query();
+
+ query.findList();
+
+ assertThat(query.getGeneratedSql()).contains("where (t0.order_date > ? or t0.order_date is null)");
+ }
+
+ @Test
+ public void ltOrNull() {
+
+ ResetBasicData.reset();
+
+ LocalDate today = LocalDate.now();
+
+ Query query = DB.find(Order.class)
+ .where().ltOrNull("orderDate", today)
+ .query();
+
+ query.findList();
+
+ assertThat(query.getGeneratedSql()).contains(" where (t0.order_date < ? or t0.order_date is null)");
+ }
+
+ @Test
+ public void inRangeWith() {
+
+ ResetBasicData.reset();
+
+ LocalDate today = LocalDate.now();
+
+ Query query = DB.find(Order.class)
+ .where().inRangeWith("orderDate", "shipDate", today)
+ .query();
+
+ query.findList();
+
+ assertThat(query.getGeneratedSql()).contains("(t0.order_date <= ? and (t0.ship_date > ? or t0.ship_date is null))");
}
}