/*
* Copyright 2015, The Querydsl Team (http://www.querydsl.com/team)
*
* Licensed 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 com.querydsl.hibernate.search;
import java.util.List;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.hibernate.Session;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import com.mysema.commons.lang.CloseableIterator;
import com.mysema.commons.lang.IteratorAdapter;
import com.querydsl.core.*;
import com.querydsl.core.support.QueryMixin;
import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.ParamExpression;
import com.querydsl.core.types.Predicate;
import com.querydsl.lucene3.LuceneSerializer;
/**
* Abstract base class for Hibernate Search query classes
*
* @param <T> result type
* @param <Q> concrete subtype
*/
public abstract class AbstractSearchQuery<T, Q extends AbstractSearchQuery<T,Q>> implements SimpleQuery<Q>, Fetchable<T> {
private final EntityPath<T> path;
private final QueryMixin<Q> queryMixin;
private final LuceneSerializer serializer;
private final FullTextSession session;
@SuppressWarnings("unchecked")
public AbstractSearchQuery(FullTextSession session, EntityPath<T> path) {
this.queryMixin = new QueryMixin<Q>((Q) this);
this.session = session;
this.path = path;
this.serializer = SearchSerializer.DEFAULT;
queryMixin.from(path);
}
public AbstractSearchQuery(Session session, EntityPath<T> path) {
this(Search.getFullTextSession(session), path);
}
@Override
public long fetchCount() {
return createQuery(true).getResultSize();
}
private FullTextQuery createQuery(boolean forCount) {
QueryMetadata metadata = queryMixin.getMetadata();
org.apache.lucene.search.Query query;
if (metadata.getWhere() != null) {
query = serializer.toQuery(metadata.getWhere(), metadata);
} else {
query = new MatchAllDocsQuery();
}
FullTextQuery fullTextQuery = session.createFullTextQuery(query, path.getType());
// order
if (!metadata.getOrderBy().isEmpty() && !forCount) {
fullTextQuery.setSort(serializer.toSort(metadata.getOrderBy()));
}
// paging
QueryModifiers modifiers = metadata.getModifiers();
if (modifiers.isRestricting() && !forCount) {
Integer limit = modifiers.getLimitAsInteger();
Integer offset = modifiers.getOffsetAsInteger();
if (limit != null) {
fullTextQuery.setMaxResults(limit.intValue());
}
if (offset != null) {
fullTextQuery.setFirstResult(offset.intValue());
}
}
return fullTextQuery;
}
@Override
public Q distinct() {
return queryMixin.distinct();
}
@Override
@SuppressWarnings("unchecked")
public CloseableIterator<T> iterate() {
return new IteratorAdapter<T>(createQuery(false).iterate());
}
@Override
public Q limit(long limit) {
return queryMixin.limit(limit);
}
@SuppressWarnings("unchecked")
@Override
public List<T> fetch() {
return createQuery(false).list();
}
@SuppressWarnings("unchecked")
@Override
public QueryResults<T> fetchResults() {
FullTextQuery query = createQuery(false);
return new QueryResults<T>(query.list(), queryMixin.getMetadata().getModifiers(), query.getResultSize());
}
@Override
public Q offset(long offset) {
return queryMixin.offset(offset);
}
@Override
public Q orderBy(OrderSpecifier<?>... o) {
return queryMixin.orderBy(o);
}
@Override
public Q restrict(QueryModifiers modifiers) {
return queryMixin.restrict(modifiers);
}
@Override
public <P> Q set(ParamExpression<P> param, P value) {
return queryMixin.set(param, value);
}
@Override
public T fetchFirst() {
return limit(1).fetchOne();
}
@SuppressWarnings("unchecked")
@Override
public T fetchOne() {
try {
return (T) createQuery(false).uniqueResult();
} catch (org.hibernate.NonUniqueResultException e) {
throw new NonUniqueResultException();
}
}
@Override
public Q where(Predicate... e) {
return queryMixin.where(e);
}
}