package hu.sch.ejb.search;
import hu.sch.domain.user.User;
import hu.sch.domain.user.User_;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
/**
* Builds the query for complex search.
*
* @author tomi
*/
public class SearchQueryBuilder {
private EntityManager em;
private final String keyword;
private Root<User> usr;
private CriteriaBuilder builder;
public SearchQueryBuilder(EntityManager em, String keyword) {
this.em = em;
this.keyword = keyword;
this.builder = em.getCriteriaBuilder();
}
public TypedQuery<User> build() {
CriteriaQuery<User> q = builder.createQuery(User.class);
usr = q.from(User.class);
prepareQuery(q);
return em.createQuery(q);
}
public TypedQuery<Long> buildForCount() {
CriteriaQuery<Long> q = builder.createQuery(Long.class);
usr = q.from(User.class);
q.select(builder.count(usr));
prepareQuery(q);
return em.createQuery(q);
}
private void prepareQuery(CriteriaQuery<?> q) {
List<Predicate> andFilters = new ArrayList<>();
for (String word : keyword.split(" ")) {
Predicate or = builder.or(
buildLikeQueryPart(usr.get(User_.firstName), word),
buildLikeQueryPart(usr.get(User_.lastName), word),
buildLikeQueryPart(usr.get(User_.nickName), word),
buildLikeQueryPart(usr.get(User_.screenName), word),
buildEmailQueryPart(word),
buildRoomNumberQueryPart(word)
);
andFilters.add(or);
}
q.where(andFilters.toArray(new Predicate[andFilters.size()]));
q.distinct(true);
}
private Predicate buildLikeQueryPart(Expression<String> expr, String word) {
return builder.like(builder.lower(expr), buildLikeString(word));
}
private String buildLikeString(String word) {
if (word == null) {
throw new IllegalArgumentException("Argument 'word' cannot be null");
}
return "%".concat(word.toLowerCase()).concat("%");
}
private Predicate buildEmailQueryPart(String word) {
return builder.and(
// and equals to the given word
builder.equal(usr.get(User_.emailAddress), word));
}
private Predicate buildRoomNumberQueryPart(String word) {
return builder.and(
// room number consists of [dormitor] [room]
builder.or(
buildLikeQueryPart(usr.get(User_.dormitory), buildLikeString(word)),
buildLikeQueryPart(usr.get(User_.room), buildLikeString(word))
)
);
}
}