/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.test.query.sorting;
import java.util.List;
import java.util.Map;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.hibernate.Transaction;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.cfg.Environment;
import org.hibernate.search.test.SearchTestBase;
import org.hibernate.search.test.query.Book;
import org.hibernate.search.testsupport.TestConstants;
import org.hibernate.search.testsupport.junit.SkipOnElasticsearch;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
/**
* Test for sorting on fields which are not added as doc value fields and thus require index uninverting.
*
* @author Gunnar Morling
*/
public class SortWithIndexUninvertingTest extends SearchTestBase {
private static FullTextSession fullTextSession;
private static QueryParser queryParser;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
fullTextSession = Search.getFullTextSession( openSession() );
queryParser = new QueryParser(
"title",
TestConstants.stopAnalyzer
);
createTestContractors();
}
@Override
@After
public void tearDown() throws Exception {
// check for ongoing transaction which is an indicator that something went wrong
// don't call the cleanup methods in this case. Otherwise the original error get swallowed
if ( fullTextSession.getTransaction().getStatus() != TransactionStatus.ACTIVE ) {
deleteTestContractors();
fullTextSession.close();
}
super.tearDown();
}
@Test
public void testCombinedQueryOnIndexWithSortFieldAndIndexToBeUninverted() throws Exception {
Transaction tx = fullTextSession.beginTransaction();
Query query = queryParser.parse( "name:Bill" );
FullTextQuery hibQuery = fullTextSession.createFullTextQuery( query, Plumber.class, BrickLayer.class );
Sort sort = new Sort( new SortField( "sortName", SortField.Type.STRING ) ); //ASC
hibQuery.setSort( sort );
@SuppressWarnings("unchecked")
List<Book> result = hibQuery.list();
assertNotNull( result );
assertThat( result ).onProperty( "name" )
.describedAs( "Expecting results from index with sort field and uninverted index in the correct sort order" )
.containsExactly( "Bill the brick layer", "Bill the plumber" );
tx.commit();
}
/**
* The index is shared by two entities. One declares the required sorts, the other does not. As this would require
* uninverting the index for one entity but not the other, that situation is considered inconsistent and an
* exception is expected.
*/
@Test
@Category(SkipOnElasticsearch.class) // This problem does not affect the Elasticsearch backend
public void testQueryOnIndexSharedByEntityWithRequiredSortFieldAndEntityWithoutRaisesException() throws Exception {
Transaction tx = fullTextSession.beginTransaction();
Query query = queryParser.parse( "name:Bill" );
FullTextQuery hibQuery = fullTextSession.createFullTextQuery( query, Thatcher.class, BrickLayer.class );
Sort sort = new Sort( new SortField( "sortName", SortField.Type.STRING ) ); //ASC
hibQuery.setSort( sort );
try {
hibQuery.list();
fail( "Expected exception was not raised" );
}
catch (Exception e) {
assertThat( e.getMessage() ).contains( "HSEARCH000298" );
}
tx.commit();
}
private void createTestContractors() {
Transaction tx = fullTextSession.beginTransaction();
fullTextSession.save( new Plumber( 1, "Bill the plumber" ) );
fullTextSession.save( new BrickLayer( 2, "Bill the brick layer", "Johnson" ) );
fullTextSession.save( new BrickLayer( 4, "Barny the brick layer", "Johnson" ) );
fullTextSession.save( new BrickLayer( 5, "Bart the brick layer", "Higgins" ) );
fullTextSession.save( new BrickLayer( 6, "Barny the brick layer", "Higgins" ) );
fullTextSession.save( new Thatcher( 3, "Bill the thatcher" ) );
tx.commit();
fullTextSession.clear();
}
private void deleteTestContractors() {
Transaction tx = fullTextSession.beginTransaction();
fullTextSession.createQuery( "delete " + Plumber.class.getName() ).executeUpdate();
fullTextSession.createQuery( "delete " + BrickLayer.class.getName() ).executeUpdate();
fullTextSession.createQuery( "delete " + Thatcher.class.getName() ).executeUpdate();
tx.commit();
fullTextSession.clear();
}
@Override
public void configure(Map<String, Object> settings) {
settings.put( Environment.INDEX_UNINVERTING_ALLOWED, "true" );
}
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class[] {
Plumber.class,
BrickLayer.class,
Thatcher.class
};
}
}