Reputation: 783
Due to a well known Hibernate+Postgres bug I decided to use Criteria API as many of my arguments can be null
(fed from REST call).
As Criteria API behaves differently with each db client I can not get the solution when it comes to dates (yyyy-MM-dd HH:mm:ss format). Anything that worked for me has not been satisfying as either I am loosing precision or I am getting exceptions. To the point:
Here is the field/column definition from my entity which maps to timestamp
column type in Postgres Database:
@Column(name = "last_modified_date",
nullable = false,
updatable = false,
columnDefinition = "TIMESTAMP WITHOUT TIME ZONE")
@Temporal(TemporalType.DATE)
protected Date lastModifiedDate;
Here is the the JpaRepository interface where I use CriteriaAPI:
public interface PageHistoryRepository extends JpaRepository<PageHistoryEntity, Long>, JpaSpecificationExecutor {
default Page<PageHistoryEntity> findPages(Date fromDate,
Date toDate,
Pageable pageable) {
return findAll(search(fromDate, toDate), pageable);
}
static Specification<PageHistoryEntity> search(Date fromDate, Date toDate) {
return (root, cq, cb) -> {
//To ensure we start with a predicate
Predicate predicate = cb.isTrue(cb.literal(true));
// this works but has no time precision
if (fromDate != null) {
Predicate _predicate = cb.greaterThanOrEqualTo(root.get(PageHistoryEntity_.lastModifiedDate.getName()).as(java.util.Date.class), fromDate);
predicate = cb.and(predicate,_predicate);
}
// this works aswell but again looses time precision
if (toDate != null) {
Predicate _predicate = cb.lessThanOrEqualTo(root.get(PageHistoryEntity_.lastModifiedDate.getName()), toDate);
predicate = cb.and(predicate,_predicate);
}
// this does not work
if (toDate != null) {
Predicate _predicate = cb.lessThanOrEqualTo(
cb.function("date_trunc", Calendar.class, cb.literal("minute"), root.get(PageHistoryEntity_.lastModifiedDate.getName()).as(Calendar.class)),
cb.function("date_trunc", Calendar.class, cb.literal("minute"), cb.literal(toDate)).as(Calendar.class));
predicate = cb.and(predicate,_predicate);
}
return predicate;
};
}
}
The last of the predicates that I was hoping for it to work throws exception:
org.postgresql.util.PSQLException: ERROR: function date_trunc(character varying, unknown) is not unique
Wskazówka: Could not choose a best candidate function. You might need to add explicit type casts.
The format of the incoming date is fine, there is the value while debugging (it corresponds to the value sent from Postman so all is ok):
Here I also provide screen how the data looks in Postgres:
My question here is, how can I filter my search results by date knowing that the user might not provide any of dates or just one of them or both of them using Criteria API+PostgreSQL? Ideally I would like to my last Predicate that uses date_trunc
to work but this is too ambitious for me now.
Upvotes: 1
Views: 1491
Reputation: 783
I guess I experimented not enough, the proper way to build such criteria that would retain the time precision:
if (toDate != null) {
Predicate _predicate = cb.lessThanOrEqualTo(
cb.function("date_trunc", Date.class, cb.literal("minute"), root.get(PageHistoryEntity_.lastModifiedDate.getName())),
toDate);
predicate = cb.and(predicate,_predicate);
}
Upvotes: 2