blob: 64c4d02d0d9aed72b93ff2471c2b512f8920ff4d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.criteria;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.apache.openjpa.kernel.Filters;
/**
* Test JDBC Escape Syntax date/time strings in query.
*
*
* @author Pinaki Poddar
*
*/
public class TestDateStringConversion extends CriteriaTest {
private static final String OPEN_BRACKET = "{";
private static final String CLOSE_BRACKET = "}";
private static final String SINGLE_QUOTE = "'";
void createData(String name) {
long now = System.currentTimeMillis();
long tomorrow = now + 24*60*60*1000+1;
Date date = new Date(tomorrow);
DependentId id = new DependentId();
id.setEffDate(date);
id.setName(name);
Dependent pc = new Dependent();
pc.setId(id);
pc.setEndDate(date);
em.getTransaction().begin();
em.persist(pc);
em.getTransaction().commit();
}
/**
* The persistent property Dependent.endDate being tested is declared as Date but mapped with
* @Temporal(TemporalType.TIMESTAMP).
*
* When executing JPQL, the query string directly uses a JDBC Escape Syntax that is passed
* to JDBC Driver and hence that string should encode a Timestamp.
*
* Criteria Query, on the other hand, must conform to the API signature and hence the expression
* that takes the JDBC Escape Syntax must be cast to Date.class to match the declared type of
* Dependent.endDate.
*
*/
public void testDateString() {
createData("testDateString");
long now = System.currentTimeMillis();
String dateString = createJDBCEscapeString(new Date(now));
String tsString = createJDBCEscapeString(new Timestamp(now));
// add Timestamp string because Dependent.endDate is mapped to TemporalType.TimeStamp
String jpql = "select d from Dependent d where d.endDate >= " + tsString + " ORDER BY d.endDate";
CriteriaQuery<Dependent> c = cb.createQuery(Dependent.class);
Root<Dependent> d = c.from(Dependent.class);
// the literal is cast to Date.class because Dependent.endDate is declared as Date
c.where(cb.greaterThanOrEqualTo(d.get(Dependent_.endDate), cb.literal(dateString).as(Date.class)));
c.orderBy(cb.asc(d.get(Dependent_.endDate)));
// can not compare SQL because JPQL and Criteria handles JDBC escape syntax in
// a different way.
assertSameResult(c, jpql);
}
/**
* A similar query but the JDBC Escape String is passed as an parameter.
* Parameter value binding is relaxed to accept the string as a value
* of temporal type instance.
* Hence does not require, as in the the earlier case, to use different
* escape string.
*/
public void testDateStringAsParameter() {
createData("testDateStringAsParameter");
long now = System.currentTimeMillis();
Date earlier = new Date(now - 1000);
final String dateString = createJDBCEscapeString(earlier);
String jpql = "select d from Dependent d where d.endDate >= :dateString ORDER BY d.endDate";
CriteriaQuery<Dependent> c = cb.createQuery(Dependent.class);
Root<Dependent> d = c.from(Dependent.class);
c.where(cb.greaterThanOrEqualTo(d.get(Dependent_.endDate), cb.parameter(String.class, "dateString")
.as(Date.class)));
c.orderBy(cb.asc(d.get(Dependent_.endDate)));
assertEquivalence(new QueryDecorator() {
@Override
public void decorate(Query q) {
q.setParameter("dateString", dateString);
}
}, c, jpql);
}
String createJDBCEscapeString(Object time) {
String key = "";
if (time instanceof Date)
key = "d ";
else if (time instanceof Time)
key = "t ";
else if (time instanceof Timestamp)
key = "ts ";
else {
fail("Wrong object " + time + " of " + time.getClass() + " for JDBC conversion");
}
return OPEN_BRACKET + key + SINGLE_QUOTE + time.toString() + SINGLE_QUOTE + CLOSE_BRACKET;
}
public void testJDBCEscapeSyntaxTimestamp() {
Timestamp ts = new Timestamp(System.currentTimeMillis());
String s = "{ts '" + ts.toString() + "'}";
assertTrue(Filters.isJDBCTemporalSyntax(s));
assertNotNull(Filters.parseJDBCTemporalSyntax(s));
Object converted = Filters.convert(s, Timestamp.class);
assertTrue(converted instanceof Timestamp);
assertEquals("Original=" + s + " Converted " + converted, ts.toString(), converted.toString());
}
public void testJDBCEscapeSyntaxTime() {
Time t = new Time(System.currentTimeMillis());
String s = "{t '" + t.toString() + "'}";
assertTrue(Filters.isJDBCTemporalSyntax(s));
assertNotNull(Filters.parseJDBCTemporalSyntax(s));
Object converted = Filters.convert(s, Time.class);
assertTrue(converted instanceof Time);
assertEquals("Original=" + s + " Converted " + converted, t.toString(), converted.toString());
}
public void testJDBCEscapeSyntaxDate() {
Date d = new Date(System.currentTimeMillis());
String s = "{d '" + d.toString() + "'}";
assertTrue(Filters.isJDBCTemporalSyntax(s));
assertNotNull(Filters.parseJDBCTemporalSyntax(s));
Object converted = Filters.convert(s, Date.class);
assertTrue(converted instanceof Date);
assertEquals("Original=" + s + " Converted " + converted, d.toString(), converted.toString());
}
void assertSameResult(CriteriaQuery<Dependent> c, String jpql) {
List<Dependent> jResult = em.createQuery(jpql).getResultList();
List<Dependent> cResult = em.createQuery(c).getResultList();
assertFalse(jResult.isEmpty());
assertEquals(cResult.size(), jResult.size());
for (int i = 0; i < jResult.size(); i++) {
assertEquals(jResult.get(i).getEndDate(), cResult.get(i).getEndDate());
}
}
}