/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.search.test.query;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.hibernate.ScrollableResults;
import org.hibernate.Transaction;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.test.util.FullTextSessionBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test for org.hibernate.search.query.ScrollableResultsImpl
*
* @see org.hibernate.search.query.hibernate.impl.ScrollableResultsImpl
* @author Sanne Grinovero
*/
public class ScrollableResultsTest {
private FullTextSessionBuilder builder;
private FullTextSession sess;
@Before
public void setUp() {
builder = new FullTextSessionBuilder();
builder
.addAnnotatedClass( AlternateBook.class )
.addAnnotatedClass( Employee.class )
.setProperty( "hibernate.default_batch_fetch_size", "10" )
.build();
sess = builder.openFullTextSession();
Transaction tx = sess.beginTransaction();
//create some entities to query:
for ( int i = 0; i < 324; i++ ) {
sess.persist( new AlternateBook( i , "book about the number " + i ) );
}
for ( int i = 0; i < 133; i++ ) {
sess.persist( new Employee( i , "Rossi", "dept. num. " + i ) );
}
tx.commit();
}
@After
public void tearDown() {
builder.close();
}
/**
* Test forward scrolling using pagination
*/
@Test
public void testScrollingForward() {
Transaction tx = sess.beginTransaction();
TermQuery tq = new TermQuery( new Term( "summary", "number") );
Sort sort = new Sort( new SortField( "id", SortField.STRING ) );
ScrollableResults scrollableResults = sess
.createFullTextQuery( tq, AlternateBook.class )
.setSort( sort )
.setFetchSize( 10 )
.setFirstResult( 20 )
.setMaxResults( 111 )
.scroll();
assertEquals( -1, scrollableResults.getRowNumber() );
assertTrue( scrollableResults.last() );
assertEquals( 110, scrollableResults.getRowNumber() );
scrollableResults.beforeFirst();
int position = scrollableResults.getRowNumber();
while ( scrollableResults.next() ) {
position++;
int bookId = position + 20;
assertEquals( position, scrollableResults.getRowNumber() );
AlternateBook book = (AlternateBook) scrollableResults.get()[0];
assertEquals( bookId, book.getId().intValue() );
assertEquals( "book about the number " + bookId, book.getSummary() );
assertTrue( sess.contains( book ) );
}
assertEquals( 110, position );
scrollableResults.close();
tx.commit();
}
/**
* Verify inverse-order scrolling.
* TODO to verify correct FetchSize behavior I've been debugging
* the behavior; we should add a mock library to automate this kind of tests.
*/
@Test
public void testScrollingBackwards() {
Transaction tx = sess.beginTransaction();
TermQuery tq = new TermQuery( new Term( "summary", "number") );
Sort sort = new Sort( new SortField( "id", SortField.STRING ) );
ScrollableResults scrollableResults = sess
.createFullTextQuery( tq, AlternateBook.class )
.setSort( sort )
.setFetchSize( 10 )
.scroll();
scrollableResults.beforeFirst();
// initial position should be -1 as in Hibernate Core
assertEquals( -1, scrollableResults.getRowNumber() );
assertTrue( scrollableResults.last() );
int position = scrollableResults.getRowNumber();
assertEquals( 323, position );
while ( scrollableResults.previous() ) {
AlternateBook book = (AlternateBook) scrollableResults.get()[0];
assertEquals( --position, book.getId().intValue() );
assertEquals( "book about the number " + position, book.getSummary() );
}
assertEquals( 0, position );
assertEquals( -1, scrollableResults.getRowNumber() );
scrollableResults.close();
tx.commit();
}
/**
* Test that all entities returned by a ScrollableResults
* are always attached to Session
*/
@Test
public void testResultsAreManaged() {
Transaction tx = sess.beginTransaction();
TermQuery tq = new TermQuery( new Term( "summary", "number") );
Sort sort = new Sort( new SortField( "id", SortField.STRING ) );
ScrollableResults scrollableResults = sess
.createFullTextQuery( tq, AlternateBook.class )
.setSort( sort )
.setFetchSize( 10 )
.scroll();
int position = -1;
while ( scrollableResults.next() ) {
position++;
AlternateBook book = (AlternateBook) scrollableResults.get()[0];
assertTrue( sess.contains( book ) );
// evict some entities:
if ( position % 3 == 0 ) {
sess.evict( book );
assertFalse( sess.contains( book ) );
}
}
//verifies it did scroll to the end:
assertEquals( 323, position );
//assert the entities are re-attached after eviction:
while ( scrollableResults.previous() ) {
position--;
AlternateBook book = (AlternateBook) scrollableResults.get()[0];
assertTrue( sess.contains( book ) );
}
assertEquals( -1, position );
sess.clear();
//assert the entities are re-attached after Session.clear:
while ( scrollableResults.next() ) {
position++;
AlternateBook book = (AlternateBook) scrollableResults.get()[0];
assertTrue( sess.contains( book ) );
}
assertEquals( 323, position );
tx.commit();
}
/**
* Verify scrolling works correctly when combined with Projection
* and that the projected entities are managed, even in case
* of evict usage for memory management.
*/
@Test
public void testScrollProjectionAndManaged() {
Transaction tx = sess.beginTransaction();
TermQuery tq = new TermQuery( new Term( "dept", "num") );
//the tests relies on the results being returned sorted by id:
Sort sort = new Sort( new SortField( "id", SortField.STRING ) );
ScrollableResults scrollableResults = sess
.createFullTextQuery( tq, Employee.class )
.setProjection(
FullTextQuery.OBJECT_CLASS,
FullTextQuery.ID,
FullTextQuery.THIS,
"lastname",
FullTextQuery.THIS
)
.setFetchSize( 10 )
.setSort( sort )
.scroll();
scrollableResults.last();
assertEquals( 132, scrollableResults.getRowNumber() );
scrollableResults.beforeFirst();
assertEquals( -1, scrollableResults.getRowNumber() );
int position = scrollableResults.getRowNumber();
while ( scrollableResults.next() ) {
position++;
Object[] objs = scrollableResults.get();
assertEquals( Employee.class, objs[0] );
assertEquals( position, objs[1] );
assertTrue( objs[2] instanceof Employee );
sess.contains( objs[2] );
assertEquals( "Rossi", objs[3] );
assertTrue( objs[4] instanceof Employee );
sess.contains( objs[4] );
assertTrue( objs[2]==objs[4] ); //projected twice the same entity
// detach some objects:
if ( position%3 == 0 ) {
sess.evict( objs[2] );
}
}
//verify we scrolled to the end:
assertEquals( 132, position );
// and now the other way around, checking entities are attached again:
while ( scrollableResults.previous() ) {
position--;
Object[] objs = scrollableResults.get();
assertTrue( objs[2] instanceof Employee );
sess.contains( objs[2] );
assertTrue( objs[4] instanceof Employee );
sess.contains( objs[4] );
assertTrue( objs[2]==objs[4] );
}
assertEquals( -1, position );
scrollableResults.close();
tx.commit();
}
}