Skip to content

Commit

Permalink
Add JPQL current date functions
Browse files Browse the repository at this point in the history
The CURRENT_TIME, CURRENT_TIMESTAMP, and CURRENT_DATE are added, as part
of the JPQL utility class.

ref my2iu#30
  • Loading branch information
aVolpe committed Jul 15, 2016
1 parent 3f83323 commit 990c747
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 1 deletion.
15 changes: 15 additions & 0 deletions jinq-jpa/main/org/jinq/jpa/JPQL.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.jinq.jpa;

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.regex.Pattern;

Expand All @@ -22,6 +25,18 @@ public static boolean like(String str, String pattern)
return like(str, pattern, "");
}

public static Date currentDate() {
return new Date(new java.util.Date().getTime());
}

public static Timestamp currentTimestamp() {
return new Timestamp(new java.util.Date().getTime());
}

public static Time currentTime() {
return new Time(new java.util.Date().getTime());
}

/**
* In-memory implementation of JPQL like.
* @param str string to search inside
Expand Down
7 changes: 7 additions & 0 deletions jinq-jpa/main/org/jinq/jpa/jpqlquery/ColumnExpressions.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ public ColumnExpressions(RowReader<T> reader)
this.reader = reader;
}

public static <U> ColumnExpressions<U> noColumn(RowReader<U> reader, Expression expr) {

ColumnExpressions<U> columnExpressions = new ColumnExpressions<>(reader);
columnExpressions.columns.add(expr);
return columnExpressions;
}

public static <U> ColumnExpressions<U> singleColumn(RowReader<U> reader, Expression expr)
{
ColumnExpressions<U> columnExpressions = new ColumnExpressions<>(reader);
Expand Down
7 changes: 7 additions & 0 deletions jinq-jpa/main/org/jinq/jpa/jpqlquery/FunctionExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ public class FunctionExpression extends Expression
List<Expression> arguments = new ArrayList<>();
String functionName;

public static FunctionExpression noParam(String name) {
FunctionExpression func = new FunctionExpression();
func.functionName = name;
return func;
}

public static FunctionExpression singleParam(String name, Expression base)
{
FunctionExpression func = new FunctionExpression();
Expand Down Expand Up @@ -40,6 +46,7 @@ public static FunctionExpression threeParam(String name, Expression param1, Expr
public void generateQuery(QueryGenerationState queryState, OperatorPrecedenceLevel operatorPrecedenceScope)
{
queryState.appendQuery(functionName);
if (arguments.isEmpty()) return;
queryState.appendQuery("(");
boolean isFirst = true;
for (Expression arg: arguments)
Expand Down
10 changes: 10 additions & 0 deletions jinq-jpa/main/org/jinq/jpa/transform/MethodChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class MethodChecker implements PathAnalysisMethodChecker
public final static MethodSignature jpqlIsIn;
public final static MethodSignature jpqlIsInList;
public final static MethodSignature jpqlListContains;
public final static MethodSignature jpqlCurrentDate;
public final static MethodSignature jpqlCurrentTimestamp;
public final static MethodSignature jpqlCurrentTime;
public final static MethodSignature mathSqrt = new MethodSignature("java/lang/Math", "sqrt", "(D)D");
public final static MethodSignature mathAbsDouble = new MethodSignature("java/lang/Math", "abs", "(D)D");
public final static MethodSignature mathAbsInt = new MethodSignature("java/lang/Math", "abs", "(I)I");
Expand All @@ -57,6 +60,10 @@ class MethodChecker implements PathAnalysisMethodChecker
jpqlIsInList = MethodSignature.fromMethod(JPQL.class.getMethod("isInList", Object.class, Collection.class));
jpqlListContains = MethodSignature.fromMethod(JPQL.class.getMethod("listContains", Collection.class, Object.class));

jpqlCurrentTimestamp = MethodSignature.fromMethod(JPQL.class.getMethod("currentTimestamp"));
jpqlCurrentDate = MethodSignature.fromMethod(JPQL.class.getMethod("currentDate"));
jpqlCurrentTime = MethodSignature.fromMethod(JPQL.class.getMethod("currentTime"));

streamSelectAll = MethodSignature.fromMethod(JinqStream.class.getMethod("selectAll", JinqStream.Join.class));
streamSelectAllList = MethodSignature.fromMethod(JinqStream.class.getMethod("selectAllList", JinqStream.JoinToIterable.class));
streamJoinList = MethodSignature.fromMethod(JinqStream.class.getMethod("joinList", JinqStream.JoinToIterable.class));
Expand All @@ -74,6 +81,9 @@ class MethodChecker implements PathAnalysisMethodChecker
jpqlFunctionStaticMethods.add(jpqlIsIn);
jpqlFunctionStaticMethods.add(jpqlIsInList);
jpqlFunctionStaticMethods.add(jpqlListContains);
jpqlFunctionStaticMethods.add(jpqlCurrentDate);
jpqlFunctionStaticMethods.add(jpqlCurrentTimestamp);
jpqlFunctionStaticMethods.add(jpqlCurrentTime);
jpqlFunctionStaticMethods.add(mathSqrt);
jpqlFunctionStaticMethods.add(mathAbsDouble);
jpqlFunctionStaticMethods.add(mathAbsInt);
Expand Down
28 changes: 27 additions & 1 deletion jinq-jpa/main/org/jinq/jpa/transform/SymbExToColumns.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,20 @@ private <U> ColumnExpressions<U> binaryOpWithNumericPromotion(String opString, T
// Handle operations with NULL separately
if (leftVal instanceof ConstantValue.NullConstant || rightVal instanceof ConstantValue.NullConstant)
return binaryOpWithNull(opString, leftVal, rightVal, passdown);
// XXX: here we need to skip this assertion because our tipes are
// not the same (example a Date and a java.sql.Date), but are comparable.
boolean skipAssert = false;
if (leftVal.getType().toString().equals("Ljava/util/Date;")) {
String name = rightVal.getType().toString();
skipAssert = name.equals("Ljava/sql/Timestamp;") ||
name.equals("Ljava/sql/Time;") ||
name.equals("Ljava/sql/Date;");
}

// Check if we have a valid numeric promotion (i.e. one side has a widening cast
// to match the type of the other side).
assert(leftVal.getType().equals(rightVal.getType())
assert(skipAssert
|| leftVal.getType().equals(rightVal.getType())
|| (leftVal.getType().getInternalName().equals("java/lang/Object") && config.isObjectEqualsSafe)// in Scala, many comparisons are done on Objects
|| (rightVal.getType().getInternalName().equals("java/lang/Object") && config.isObjectEqualsSafe));
if (isWideningCast(leftVal))
Expand Down Expand Up @@ -709,6 +720,21 @@ else if (sig.equals(MethodChecker.mathSqrt))
return ColumnExpressions.singleColumn(new SimpleRowReader<>(),
FunctionExpression.singleParam("SQRT", base.getOnlyColumn()));
}
else if (sig.equals(MethodChecker.jpqlCurrentDate))
{
return ColumnExpressions.noColumn(new SimpleRowReader<>(),
FunctionExpression.noParam("CURRENT_DATE"));
}
else if (sig.equals(MethodChecker.jpqlCurrentTimestamp))
{
return ColumnExpressions.noColumn(new SimpleRowReader<>(),
FunctionExpression.noParam("CURRENT_TIMESTAMP"));
}
else if (sig.equals(MethodChecker.jpqlCurrentTime))
{
return ColumnExpressions.noColumn(new SimpleRowReader<>(),
FunctionExpression.noParam("CURRENT_TIME"));
}
throw new TypedValueVisitorException("Do not know how to translate the method " + sig + " into a JPQL function");
}
else
Expand Down
68 changes: 68 additions & 0 deletions jinq-jpa/test/org/jinq/jpa/JPQLCurrentDateTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.jinq.jpa;

import static org.junit.Assert.assertEquals;

import java.util.List;

import org.jinq.jpa.test.entities.Sale;
import org.junit.Test;

public class JPQLCurrentDateTest extends JinqJPATestBase
{

@Test
public void testCurrentTimeStamp()
{
List<Sale> list = streams.streamAll(em, Sale.class)
.where(s -> s.getSqlTimestamp().before(JPQL.currentTimestamp()))
.sortedBy(s -> s.getCustomer().getName())
.toList();


assertEquals("SELECT A FROM Sale A WHERE A.sqlTimestamp < CURRENT_TIMESTAMP ORDER BY A.customer.name ASC", query);
assertEquals(6, list.size());
assertEquals("Alice", list.get(0).getCustomer().getName());
}

@Test
public void testCurrentTimeStampWithUtilDate()
{
List<Sale> list = streams.streamAll(em, Sale.class)
.where(s -> s.getDate().before(JPQL.currentTimestamp()))
.sortedBy(s -> s.getCustomer().getName())
.toList();


assertEquals("SELECT A FROM Sale A WHERE A.date < CURRENT_TIMESTAMP ORDER BY A.customer.name ASC", query);
assertEquals(6, list.size());
assertEquals("Alice", list.get(0).getCustomer().getName());
}

@Test
public void testCurrentTime()
{
List<Sale> list = streams.streamAll(em, Sale.class)
.where(s -> s.getSqlTime().before(JPQL.currentTime()))
.sortedBy(s -> s.getCustomer().getName())
.toList();


assertEquals("SELECT A FROM Sale A WHERE A.sqlTime < CURRENT_TIME ORDER BY A.customer.name ASC", query);
assertEquals(6, list.size());
assertEquals("Alice", list.get(0).getCustomer().getName());
}

@Test
public void testCurrentDate()
{
List<Sale> list = streams.streamAll(em, Sale.class)
.where(s -> s.getSqlDate().before(JPQL.currentDate()))
.sortedBy(s -> s.getCustomer().getName())
.toList();


assertEquals("SELECT A FROM Sale A WHERE A.sqlDate < CURRENT_DATE ORDER BY A.customer.name ASC", query);
assertEquals(6, list.size());
assertEquals("Alice", list.get(0).getCustomer().getName());
}
}

0 comments on commit 990c747

Please sign in to comment.