/*
* 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.backend;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.apache.lucene.search.Query;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
import org.hibernate.search.backend.impl.DeleteByQuerySupport;
import org.hibernate.search.backend.spi.DeleteByQueryWork;
import org.hibernate.search.backend.spi.DeletionQuery;
import org.hibernate.search.backend.spi.SingularTermDeletionQuery;
import org.hibernate.search.backend.spi.Work;
import org.hibernate.search.backend.spi.WorkType;
import org.hibernate.search.backend.spi.Worker;
import org.hibernate.search.engine.integration.impl.ExtendedSearchIntegrator;
import org.hibernate.search.query.engine.spi.HSQuery;
import org.hibernate.search.testsupport.junit.SearchFactoryHolder;
import org.hibernate.search.testsupport.setup.TransactionContextForTest;
import org.junit.Rule;
import org.junit.Test;
/**
* @author Martin Braun
*/
public class DeleteByQueryTest {
@Rule
public SearchFactoryHolder factoryHolder = new SearchFactoryHolder( Book.class, Movie.class );
@Test
public void testStringSerialization() {
for ( DeletionQuery q : this.buildQueries() ) {
this.testSerializationForQuery( q );
}
}
private List<DeletionQuery> buildQueries() {
List<DeletionQuery> l = new ArrayList<>();
l.add( new SingularTermDeletionQuery( "id", "123" ) );
l.addAll( this.buildNumQueries() );
return l;
}
private List<SingularTermDeletionQuery> buildNumQueries() {
List<SingularTermDeletionQuery> l = new ArrayList<>();
{
l.add( new SingularTermDeletionQuery( "intField", 1 ) );
l.add( new SingularTermDeletionQuery( "longField", 1L ) );
l.add( new SingularTermDeletionQuery( "floatField", 1F ) );
l.add( new SingularTermDeletionQuery( "doubleField", 1D ) );
}
return l;
}
private List<Integer> expectedCount() {
List<Integer> l = new ArrayList<>();
l.add( 1 );
l.add( 1 );
l.add( 1 );
l.add( 1 );
return l;
}
@Test
public void testSingularTermQuery() {
ExtendedSearchIntegrator integrator = this.factoryHolder.getSearchFactory();
Worker worker = integrator.getWorker();
{
TransactionContextForTest tc = new TransactionContextForTest();
for ( Work work : this.makeBooksForSingularTermQuery() ) {
worker.performWork( work, tc );
}
tc.end();
}
this.assertCount( Book.class, 2, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new DeleteByQueryWork( Book.class, new SingularTermDeletionQuery( "url", "lordoftherings" ) ), tc );
tc.end();
}
this.assertCount( Book.class, 1, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new DeleteByQueryWork( Book.class, new SingularTermDeletionQuery( "url", "thehobbit" ) ), tc );
tc.end();
}
this.assertCount( Book.class, 0, integrator );
// this should stay empty now!
}
@Test
public void testStringIdTermQuery() {
ExtendedSearchIntegrator integrator = this.factoryHolder.getSearchFactory();
Worker worker = integrator.getWorker();
{
TransactionContextForTest tc = new TransactionContextForTest();
for ( Work work : this.makeBooksForSingularTermQuery() ) {
worker.performWork( work, tc );
}
tc.end();
}
this.assertCount( Book.class, 2, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new DeleteByQueryWork( Book.class, new SingularTermDeletionQuery( "id", String.valueOf( 5 ) ) ), tc );
tc.end();
}
this.assertCount( Book.class, 1, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new DeleteByQueryWork( Book.class, new SingularTermDeletionQuery( "id", String.valueOf( 6 ) ) ), tc );
tc.end();
}
this.assertCount( Book.class, 0, integrator );
// this should stay empty now!
}
@Test
public void testNumericIdTermQuery() {
ExtendedSearchIntegrator integrator = this.factoryHolder.getSearchFactory();
Worker worker = integrator.getWorker();
{
TransactionContextForTest tc = new TransactionContextForTest();
for ( Work work : this.makeMoviesForNumericIdTermQuery() ) {
worker.performWork( work, tc );
}
tc.end();
}
this.assertCount( Movie.class, 2, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new DeleteByQueryWork( Movie.class, new SingularTermDeletionQuery( "id", 3 ) ), tc );
tc.end();
}
this.assertCount( Movie.class, 1, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new DeleteByQueryWork( Movie.class, new SingularTermDeletionQuery( "id", 4 ) ), tc );
tc.end();
}
this.assertCount( Movie.class, 0, integrator );
// this should stay empty now!
}
@Test
public void testNumRangeQuery() {
ExtendedSearchIntegrator integrator = this.factoryHolder.getSearchFactory();
List<SingularTermDeletionQuery> numQueries = this.buildNumQueries();
List<Integer> expectedCount = this.expectedCount();
assertEquals( expectedCount.size(), numQueries.size() );
for ( int i = 0; i < numQueries.size(); ++i ) {
try {
this.testForQuery( Book.class, integrator, numQueries.get( i ), expectedCount.get( i ) );
}
catch (Throwable e) {
System.out.println( "ERROR: " + numQueries.get( i ) + ". expected was: " + expectedCount.get( i ) );
throw e;
}
}
}
private void testForQuery(Class<?> entityType, ExtendedSearchIntegrator integrator, DeletionQuery query, int expectedCount) {
Worker worker = integrator.getWorker();
{
TransactionContextForTest tc = new TransactionContextForTest();
for ( Work work : this.makeBooksForNumRangeQuery() ) {
worker.performWork( work, tc );
}
tc.end();
}
this.assertCount( entityType, 2, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new DeleteByQueryWork( Book.class, query ), tc );
tc.end();
}
this.assertCount( entityType, expectedCount, integrator );
{
TransactionContextForTest tc = new TransactionContextForTest();
worker.performWork( new Work( Book.class, null, WorkType.PURGE_ALL ), tc );
tc.end();
}
this.assertCount( entityType, 0, integrator );
}
private void assertCount(Class<?> entityType, int count, ExtendedSearchIntegrator integrator) {
{
Query query = integrator.buildQueryBuilder().forEntity( Book.class ).get().all().createQuery();
HSQuery hsQuery = integrator.createHSQuery( query, entityType );
assertEquals( count, hsQuery.queryResultSize() );
}
}
private void testSerializationForQuery(DeletionQuery deletionQuery) {
assertTrue( DeleteByQuerySupport.isSupported( deletionQuery.getClass() ) );
String[] strRep = deletionQuery.serialize();
DeletionQuery copy = DeleteByQuerySupport.fromString( deletionQuery.getQueryKey(), strRep );
assertEquals( deletionQuery, copy );
}
private List<Work> makeBooksForSingularTermQuery() {
List<Work> list = new LinkedList<>();
// just some random data:
list.add( new Work( new Book( String.valueOf( 5 ), "Lord of The Rings", "lordoftherings" ), WorkType.ADD ) );
list.add( new Work( new Book( String.valueOf( 6 ), "The Hobbit", "thehobbit" ), WorkType.ADD ) );
return list;
}
private List<Work> makeMoviesForNumericIdTermQuery() {
List<Work> list = new LinkedList<>();
// just some random data:
list.add( new Work( new Movie( 3, "Cashback" ), WorkType.ADD ) );
list.add( new Work( new Movie( 4, "Garden state" ), WorkType.ADD ) );
return list;
}
private List<Work> makeBooksForNumRangeQuery() {
List<Work> list = new LinkedList<>();
// just some random data:
list.add( new Work( new Book( String.valueOf( 5 ), 1, 1L, 1F, 1D, "Lord of The Rings", "lordoftherings" ), WorkType.ADD ) );
list.add( new Work( new Book( String.valueOf( 6 ), 2, 2L, 2F, 2D, "The Hobbit", "thehobbit" ), WorkType.ADD ) );
return list;
}
@Indexed(index = "books")
private static class Book {
@DocumentId
String id;
@Field(store = Store.YES, index = Index.YES)
Integer intField;
@Field(store = Store.YES, index = Index.YES)
Long longField;
@Field(store = Store.YES, index = Index.YES)
Float floatField;
@Field(store = Store.YES, index = Index.YES)
Double doubleField;
@Field
String title;
@Field
String url;
public Book(String id, String title, String url) {
this.id = id;
this.title = title;
this.url = url;
}
public Book(String id, Integer intField, Long longField, Float floatField, Double doubleField, String title, String url) {
this.id = id;
this.intField = intField;
this.longField = longField;
this.floatField = floatField;
this.doubleField = doubleField;
this.title = title;
this.url = url;
}
}
@Indexed(index = "movies")
private static class Movie {
@DocumentId
Integer id;
@Field
String title;
public Movie(Integer id, String title) {
this.id = id;
this.title = title;
}
}
}