blob: ecd727673b9cdaa26c7838294323009453232d2d [file] [log] [blame]
/*
* Copyright 2008 Alin Dreghiciu.
*
* 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 org.qi4j.runtime.query;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.qi4j.api.activation.ActivationException;
import org.qi4j.api.query.Query;
import org.qi4j.api.query.QueryBuilder;
import org.qi4j.api.query.QueryBuilderFactory;
import org.qi4j.api.query.QueryExpressions;
import org.qi4j.api.query.grammar.OrderBy;
import org.qi4j.api.unitofwork.UnitOfWork;
import org.qi4j.api.unitofwork.UnitOfWorkCompletionException;
import org.qi4j.bootstrap.AssemblyException;
import org.qi4j.bootstrap.ClassScanner;
import org.qi4j.bootstrap.ModuleAssembly;
import org.qi4j.bootstrap.SingletonAssembler;
import org.qi4j.runtime.query.model.City;
import org.qi4j.runtime.query.model.Describable;
import org.qi4j.runtime.query.model.Domain;
import org.qi4j.runtime.query.model.Female;
import org.qi4j.runtime.query.model.Male;
import org.qi4j.runtime.query.model.Nameable;
import org.qi4j.runtime.query.model.Person;
import org.qi4j.runtime.query.model.Pet;
import org.qi4j.runtime.query.model.entities.DomainEntity;
import org.qi4j.runtime.query.model.entities.PetEntity;
import org.qi4j.runtime.query.model.values.ContactValue;
import org.qi4j.runtime.query.model.values.ContactsValue;
import org.qi4j.spi.query.EntityFinderException;
import org.qi4j.test.EntityTestAssembler;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.qi4j.api.query.QueryExpressions.eq;
import static org.qi4j.api.query.QueryExpressions.ge;
import static org.qi4j.api.query.QueryExpressions.gt;
import static org.qi4j.api.query.QueryExpressions.isNotNull;
import static org.qi4j.api.query.QueryExpressions.isNull;
import static org.qi4j.api.query.QueryExpressions.lt;
import static org.qi4j.api.query.QueryExpressions.matches;
import static org.qi4j.api.query.QueryExpressions.not;
import static org.qi4j.api.query.QueryExpressions.or;
import static org.qi4j.api.query.QueryExpressions.orderBy;
import static org.qi4j.api.query.QueryExpressions.property;
import static org.qi4j.api.query.QueryExpressions.templateFor;
public class IterableQuerySourceTest
{
private UnitOfWork uow;
private QueryBuilderFactory qbf;
@Before
public void setUp()
throws UnitOfWorkCompletionException, ActivationException, AssemblyException
{
SingletonAssembler assembler = new SingletonAssembler()
{
public void assemble( ModuleAssembly module )
throws AssemblyException
{
Iterable<Class<?>> entities = ClassScanner.findClasses( DomainEntity.class );
for( Class entity : entities )
{
module.entities( entity );
}
module.values( ContactsValue.class, ContactValue.class );
new EntityTestAssembler().assemble( module );
}
};
uow = assembler.module().newUnitOfWork();
Network.populate( uow, assembler.module() );
uow.complete();
uow = assembler.module().newUnitOfWork();
Network.refresh( uow );
qbf = assembler.module();
}
@After
public void tearDown()
{
if( uow != null )
{
uow.discard();
}
}
private static void verifyUnorderedResults( final Iterable<? extends Nameable> results,
final String... names
)
{
final List<String> expected = new ArrayList<String>( Arrays.asList( names ) );
for( Nameable entity : results )
{
String name = entity.name().get();
assertTrue( name + " returned but not expected", expected.remove( name ) );
}
for( String notReturned : expected )
{
fail( notReturned + " was expected but not returned" );
}
}
private static void verifyOrderedResults( final Iterable<? extends Nameable> results,
final String... names
)
{
final List<String> expected = new ArrayList<String>( Arrays.asList( names ) );
for( Nameable entity : results )
{
String firstExpected = null;
if( expected.size() > 0 )
{
firstExpected = expected.get( 0 );
}
if( firstExpected == null )
{
fail( entity.name().get() + " returned but not expected" );
}
else if( !firstExpected.equals( entity.name().get() ) )
{
fail( entity.name().get() + " is not in the expected order" );
}
expected.remove( 0 );
}
for( String notReturned : expected )
{
fail( notReturned + " was expected but not returned" );
}
}
@Test
public void givenQueryWhenExecutedReturnAll()
throws EntityFinderException
{
final QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
final Query<Person> query = qb.newQuery( Network.persons() );
System.out.println( query );
verifyUnorderedResults( query, "Joe Doe", "Ann Doe", "Jack Doe", "Vivian Smith" );
}
@Test
public void givenEqQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Domain> qb = qbf.newQueryBuilder( Domain.class );
final Nameable nameable = templateFor( Nameable.class );
final Query<Domain> query = qb.where(
eq( nameable.name(), "Gaming" )
).newQuery( Network.domains() );
verifyUnorderedResults( query, "Gaming" );
}
@Test
public void givenMixinTypeQueryWhenExecutedReturnAll()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
Query<Nameable> query = qb.newQuery( Network.nameables() );
verifyUnorderedResults(
query,
"Joe Doe", "Ann Doe", "Jack Doe", "Vivian Smith",
"Penang", "Kuala Lumpur",
"Cooking", "Gaming", "Programming", "Cars"
);
}
@Test
public void givenEqQueryOnValueWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person personTemplate = templateFor( Person.class );
City placeOfBirth = personTemplate.placeOfBirth().get();
Query<Person> query = qb.where(
eq( placeOfBirth.name(), "Kuala Lumpur" )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Joe Doe", "Ann Doe", "Vivian Smith" );
}
@Test
public void givenEqQueryOnAssociationAndPropertyWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
eq( person.mother().get().placeOfBirth().get().name(), "Kuala Lumpur" )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Joe Doe" );
}
@Test
public void givenEqQueryOnAssociationWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
City kl = uow.get( City.class, "kualalumpur" );
Query<Person> query = qb.where(
eq( person.mother().get().placeOfBirth(), kl )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Joe Doe" );
}
@Test
public void givenGeQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
ge( person.yearOfBirth(), 1973 )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Joe Doe", "Ann Doe", "Vivian Smith" );
}
@Test
public void givenAndQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
Person person = templateFor( Person.class );
Query<Nameable> query = qb.where(
ge( person.yearOfBirth(), 1900 ).and( eq( person.placeOfBirth().get().name(), "Penang" ) )
).newQuery( Network.nameables() );
verifyUnorderedResults( query, "Jack Doe" );
}
@Test
public void givenMultipleAndQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
Person person = templateFor( Person.class );
Query<Nameable> query = qb.where(
ge( person.yearOfBirth(), 1900 ).
and( lt( person.yearOfBirth(), 2000 ) ).
and( eq( person.placeOfBirth().get().name(), "Penang" ) )
).newQuery( Network.nameables() );
verifyUnorderedResults( query, "Jack Doe" );
}
@Test
public void givenOrQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
or(
eq( person.yearOfBirth(), 1970 ),
eq( person.yearOfBirth(), 1975 )
)
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Jack Doe", "Ann Doe" );
}
@Test
public void givenMultipleOrQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
or(
eq( person.yearOfBirth(), 1970 ),
eq( person.yearOfBirth(), 1975 ),
eq( person.yearOfBirth(), 1990 )
)
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Jack Doe", "Ann Doe", "Joe Doe" );
}
@Test
public void givenOrQueryOnFemalesWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Female> qb = qbf.newQueryBuilder( Female.class );
Person person = templateFor( Person.class );
Query<Female> query = qb.where(
or(
eq( person.yearOfBirth(), 1970 ),
eq( person.yearOfBirth(), 1975 )
)
).newQuery( Network.females() );
verifyUnorderedResults( query, "Ann Doe" );
}
@Test
public void givenNotQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
not(
eq( person.yearOfBirth(), 1975 )
)
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Jack Doe", "Joe Doe", "Vivian Smith" );
}
@Test
public void givenIsNotNullQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
isNotNull( person.email() )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Joe Doe", "Vivian Smith" );
}
@Test
public void givenIsNullQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
isNull( person.email() )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Ann Doe", "Jack Doe" );
}
@Test
public void givenIsNotNullOnMixinTypeWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Male person = templateFor( Male.class );
Query<Person> query = qb.where(
isNotNull( person.wife() )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Jack Doe" );
}
@Test
public void givenIsNullOnMixinTypeWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Male> qb = qbf.newQueryBuilder( Male.class );
Male person = templateFor( Male.class );
Query<Male> query = qb.where(
isNull( person.wife() )
).newQuery( Network.males() );
verifyUnorderedResults( query, "Joe Doe" );
}
@Test
public void givenIsNullOnAssociationWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Male person = templateFor( Male.class );
Query<Person> query = qb.where(
isNull( person.wife() )
).newQuery( Network.persons() );
verifyUnorderedResults( query, "Joe Doe", "Ann Doe", "Vivian Smith" );
}
@Test
public void givenOrderAndMaxResultsQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
// should return only 2 entities
Nameable nameable = templateFor( Nameable.class );
Query<Nameable> query = qb.newQuery( Network.nameables() );
query.orderBy( orderBy( nameable.name() ) );
query.maxResults( 2 );
verifyOrderedResults(
query,
"Ann Doe", "Cars"
);
}
@Test
public void givenOrderAndFirstAndMaxResultsQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
// should return only 3 entities starting with forth one
Nameable nameable = templateFor( Nameable.class );
Query<Nameable> query = qb.newQuery( Network.nameables() );
query.orderBy( orderBy( nameable.name() ) );
query.firstResult( 3 );
query.maxResults( 3 );
verifyOrderedResults(
query,
"Gaming", "Jack Doe", "Joe Doe"
);
}
@Test
public void givenOrderByOnMixinTypeQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
// should return all Nameable entities sorted by name
Nameable nameable = templateFor( Nameable.class );
Query<Nameable> query = qb.newQuery( Network.nameables() );
query.orderBy( orderBy( nameable.name() ) );
verifyOrderedResults(
query,
"Ann Doe", "Cars", "Cooking", "Gaming", "Jack Doe", "Joe Doe", "Kuala Lumpur", "Penang", "Programming", "Vivian Smith"
);
}
@Test
public void givenGtAndOrderByQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
// should return all Nameable entities with a name > "D" sorted by name
Nameable nameable = templateFor( Nameable.class );
Query<Nameable> query = qb.where(
gt( nameable.name(), "D" )
).newQuery( Network.nameables() );
query.orderBy( orderBy( nameable.name() ) );
verifyOrderedResults(
query,
"Gaming", "Jack Doe", "Joe Doe", "Kuala Lumpur", "Penang", "Programming", "Vivian Smith"
);
}
@Test
public void givenGtAndOrderByDescendingQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
// should return all Persons born after 1973 (Ann and Joe Doe) sorted descending by name
Person person = templateFor( Person.class );
Query<Person> query = qb.where(
gt( person.yearOfBirth(), 1973 )
).newQuery( Network.persons() );
query.orderBy( orderBy( person.name(), OrderBy.Order.DESCENDING ) );
verifyOrderedResults( query, "Vivian Smith", "Joe Doe", "Ann Doe" );
}
@Test
public void givenOrderByMultipleQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
// should return all Persons sorted by name of the city they were born, and then by year they were born
Person person = templateFor( Person.class );
Query<Person> query = qb.newQuery( Network.persons() );
query.orderBy( orderBy( person.placeOfBirth().get().name() ),
orderBy( person.yearOfBirth() ) );
verifyOrderedResults( query, "Ann Doe", "Joe Doe", "Vivian Smith", "Jack Doe" );
}
@Test
public void givenMatchesQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Nameable> qb = qbf.newQueryBuilder( Nameable.class );
Nameable nameable = templateFor( Nameable.class );
// should return Jack and Joe Doe
Query<Nameable> query = qb.where(
matches( nameable.name(), "J.*Doe" )
).newQuery( Network.nameables() );
verifyUnorderedResults(
query,
"Jack Doe", "Joe Doe"
);
}
// TODO solve ManyAssociation filtering for iterables
// @Test
public void givenOneOfQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Domain interests = person.interests().get( 0 );
Query<Person> query = qb.where( eq( interests.name(), "Cars" ) ).newQuery( Network.persons() );
verifyOrderedResults( query, "Jack Doe" );
}
@Test
public void givenManyAssociationContainsQueryWhenExecutedThenReturnCorrect()
throws EntityFinderException
{
QueryBuilder<Person> qb = qbf.newQueryBuilder( Person.class );
Person person = templateFor( Person.class );
Domain value = Network.domains().iterator().next();
Query<Person> query = qb.where( QueryExpressions.contains( person.interests(), value ) )
.newQuery( Network.persons() );
for( Person person1 : query )
{
System.out.println( person1.name() );
}
verifyOrderedResults( query, "Joe Doe", "Vivian Smith" );
}
@Test
public void givenEntitiesWithInternalStateWhenQueriedThenReturnCorrect()
{
QueryBuilder<PetEntity> qb = qbf.newQueryBuilder( PetEntity.class );
Pet.PetState pet = templateFor( Pet.PetState.class );
Nameable petOwner = templateFor( Nameable.class, pet.owner() );
Query<PetEntity> query = qb.where( eq( petOwner.name(), "Jack Doe" ) ).newQuery( Network.pets() );
verifyOrderedResults( query, "Rex" );
}
@Test
public void givenEntitiesWithFieldPropertyByNameWhenQueriedThenReturnCorrect()
{
QueryBuilder<PetEntity> qb = qbf.newQueryBuilder( PetEntity.class );
Query<PetEntity> query = qb.where( eq( property( Describable.Mixin.class, "description" ), "Rex is a great dog" ) )
.newQuery( Network.pets() );
verifyOrderedResults( query, "Rex" );
}
@Test
public void givenEntitiesWithFieldPropertyWhenQueriedThenReturnCorrect()
{
QueryBuilder<PetEntity> qb = qbf.newQueryBuilder( PetEntity.class );
Query<PetEntity> query = qb.where( eq( templateFor( Describable.Mixin.class ).description, "Rex is a great dog" ) )
.newQuery( Network.pets() );
verifyOrderedResults( query, "Rex" );
}
}