/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* 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.ogm.datastore.mongodb.test.query.nativequery;
import static org.fest.assertions.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.hibernate.ogm.backendtck.jpa.Poem;
import org.hibernate.ogm.utils.PackagingRule;
import org.hibernate.ogm.utils.TestForIssue;
import org.hibernate.ogm.utils.jpa.OgmJpaTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
/**
* Test the execution of native queries on MongoDB using the {@link EntityManager}
*
* @author Davide D'Alto <davide@hibernate.org>
*/
public class MongoDBEntityManagerNativeQueryTest extends OgmJpaTestCase {
@Rule
public PackagingRule packaging = new PackagingRule( "persistencexml/ogm.xml", Poem.class );
private final OscarWildePoem portia = new OscarWildePoem( 1L, "Portia", "Oscar Wilde", 1881 );
private final OscarWildePoem athanasia = new OscarWildePoem( 2L, "Athanasia", "Oscar Wilde", (byte) 5 );
private final Poet christian = new Poet( "christian", "Christian Abendsonne" );
private final Poet james = new Poet( "james", "James Krass" );
private final LiteratureSociety stencilClub = new LiteratureSociety( "stencil-club", "Stencil Club Germany", christian, james );
private final Critic critic = new Critic( new CriticId( "de", "764" ), "Roger" );
private EntityManager em;
@Before
public void init() throws Exception {
// prepare test data
em = createEntityManager();
begin();
em = persist( portia, athanasia, stencilClub, critic );
commit();
em.close();
em = createEntityManager();
}
@After
public void tearDown() throws Exception {
begin();
delete( portia, athanasia, stencilClub, critic );
commit();
close( em );
}
@Test
public void testSingleResultQuery() throws Exception {
begin();
String nativeQuery = "{ $and: [ { name : 'Portia' }, { author : 'Oscar Wilde' } ] }";
OscarWildePoem poem = (OscarWildePoem) em.createNativeQuery( nativeQuery, OscarWildePoem.class ).getSingleResult();
assertAreEquals( portia, poem );
commit();
}
@Test
public void testSingleResultQueryWithProjection() throws Exception {
begin();
String nativeQuery = "db.WILDE_POEM.find( "
+ "{ '$and' : [ { 'name' : 'Portia' }, { 'author' : 'Oscar Wilde' } ] }, "
+ "{ 'name' : 1 }"
+ " )";
String result = (String) em.createNativeQuery( nativeQuery, "poemNameMapping" ).getSingleResult();
assertThat( result ).isEqualTo( "Portia" );
nativeQuery = "db.WILDE_POEM.findOne( "
+ "{ '$and' : [ { 'name' : 'Portia' }, { 'author' : 'Oscar Wilde' } ] }, "
+ "{ 'name' : 1 }"
+ " )";
result = (String) em.createNativeQuery( nativeQuery, "poemNameMapping" ).getSingleResult();
assertThat( result ).isEqualTo( "Portia" );
commit();
}
@Test
public void testSingleResultQueryWithSeveralProjections() throws Exception {
begin();
String nativeQuery = "db.WILDE_POEM.find( "
+ "{ '$and' : [ { 'name' : 'Portia' }, { 'author' : 'Oscar Wilde' } ] }, "
+ "{ 'name' : 1, 'author' : 1 }"
+ " )";
Object[] result = (Object[]) em.createNativeQuery( nativeQuery, "poemNameAuthorIdMapping" ).getSingleResult();
assertThat( Arrays.asList( result ) ).containsExactly( "Portia", "Oscar Wilde", 1L );
nativeQuery = "db.WILDE_POEM.findOne( "
+ "{ '$and' : [ { 'name' : 'Portia' }, { 'author' : 'Oscar Wilde' } ] }, "
+ "{ 'name' : 1, 'author' : 1 }"
+ " )";
result = (Object[]) em.createNativeQuery( nativeQuery, "poemNameAuthorIdMapping" ).getSingleResult();
assertThat( Arrays.asList( result ) ).containsExactly( "Portia", "Oscar Wilde", 1L );
@SuppressWarnings("unchecked")
List<Object[]> results = em.createNativeQuery( nativeQuery, "poemNameAuthorIdMapping" ).getResultList();
assertThat( results ).isNotNull();
assertThat( results.size() ).isEqualTo( 1 );
assertThat( Arrays.asList( results.get( 0 ) ) ).containsExactly( "Portia", "Oscar Wilde", 1L );
commit();
}
@Test
public void testCountQuery() throws Exception {
begin();
Long result = (Long) em.createNamedQuery( "CountPoems" ).getSingleResult();
assertThat( result ).isEqualTo( 2L );
commit();
}
@Test
public void testSingleResultFromNamedNativeQuery() throws Exception {
begin();
OscarWildePoem poem = (OscarWildePoem) em.createNamedQuery( "AthanasiaQuery" ).getSingleResult();
assertAreEquals( athanasia, poem );
commit();
}
@Test
public void testSingleProjectionResultFromNamedNativeQuery() throws Exception {
begin();
String result = (String) em.createNamedQuery( "AthanasiaProjectionQuery" ).getSingleResult();
assertThat( result ).isEqualTo( athanasia.getName() );
commit();
}
@Test
@Ignore
// TODO OGM-564 Re-enable once HHH-8237 is resolved and we're on ORM 4.3.6
public void testProjectionQueryWithTypeConversion() throws Exception {
begin();
List<Byte> result = em.createNamedQuery( "PoemRatings" ).getResultList();
assertThat( result ).containsOnly( portia.getRating(), athanasia.getRating() );
commit();
}
@Test
public void testMappedEntityResultFromNamedNativeQuery() throws Exception {
begin();
OscarWildePoem poem = (OscarWildePoem) em.createNamedQuery( "AthanasiaQueryWithMapping" ).getSingleResult();
assertAreEquals( athanasia, poem );
commit();
}
@Test
public void testExceptionWhenReturnedEntityIsMissing() throws Exception {
begin();
String nativeQuery = "{ $and: [ { name : 'Portia' }, { author : 'Oscar Wilde' } ] }";
try {
em.createNativeQuery( nativeQuery ).getSingleResult();
commit();
}
catch (Exception he) {
rollback();
String message = he.getMessage();
assertThat( message )
.as( "The native query doesn't define a returned entity, there should be a specific exception" )
.contains( "OGM001217" );
}
}
@Test
public void testListMultipleResultQuery() throws Exception {
begin();
String nativeQuery = "{ $query : { author : 'Oscar Wilde' }, $orderby : { name : 1 } }";
@SuppressWarnings("unchecked")
List<OscarWildePoem> results = em.createNativeQuery( nativeQuery, OscarWildePoem.class ).getResultList();
assertThat( results ).as( "Unexpected number of results" ).hasSize( 2 );
assertAreEquals( athanasia, results.get( 0 ) );
assertAreEquals( portia, results.get( 1 ) );
commit();
}
@Test
@SuppressWarnings("unchecked")
@TestForIssue(jiraKey = "OGM-424")
public void testEntitiesInsertedInCurrentSessionAreFoundByNativeQuery() throws Exception {
begin();
String nativeQuery = "{ name : 'Her Voice' }";
Query query = em.createNativeQuery( nativeQuery, OscarWildePoem.class );
List<OscarWildePoem> results = query.getResultList();
assertThat( results ).as( "Unexpected number of results" ).hasSize( 0 );
OscarWildePoem voice = new OscarWildePoem( 3L, "Her Voice", "Oscar Wilde", 1881 );
em.persist( voice );
results = query.getResultList();
assertThat( results ).as( "Unexpected number of results" ).hasSize( 1 );
assertAreEquals( voice, results.get( 0 ) );
em.remove( voice );
commit();
}
@Test
public void testSingleResultQueryUsingExtendedSyntax() throws Exception {
begin();
String nativeQuery = "db.WILDE_POEM.find({ '$query' : { 'name' : 'Athanasia' }, '$orderby' : { 'name' : 1 } })";
@SuppressWarnings("unchecked")
List<OscarWildePoem> results = em.createNativeQuery( nativeQuery, OscarWildePoem.class ).getResultList();
assertThat( results ).as( "Unexpected number of results" ).hasSize( 1 );
assertAreEquals( athanasia, results.get( 0 ) );
commit();
}
@Test
@TestForIssue(jiraKey = "OGM-638")
public void canRunSameNativeQuerySeveralTimes() throws Exception {
begin();
Query createNativeQuery = em.createNativeQuery(
"db.LiteratureSociety.find( { 'name' : 'Stencil Club Germany' } )",
LiteratureSociety.class
);
LiteratureSociety stencilClub = (LiteratureSociety) createNativeQuery.getSingleResult();
assertThat( stencilClub.getMembers() ).onProperty( "id" ).containsOnly( "christian", "james" );
stencilClub = (LiteratureSociety) createNativeQuery.getSingleResult();
assertThat( stencilClub.getMembers() ).onProperty( "id" ).containsOnly( "christian", "james" );
commit();
}
@Test
@TestForIssue(jiraKey = "OGM-702")
public void testQueryWithCompositeId() throws Exception {
begin();
@SuppressWarnings("unchecked")
List<Critic> critics = em.createNativeQuery( "{}", Critic.class ).getResultList();
assertThat( critics ).onProperty( "id" ).containsExactly( new CriticId( "de", "764" ) );
commit();
}
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { OscarWildePoem.class, LiteratureSociety.class, Poet.class, Critic.class };
}
private EntityManager persist(Object... entities) {
for ( Object object : entities ) {
em.persist( object );
}
return em;
}
private void assertAreEquals(OscarWildePoem expectedPoem, OscarWildePoem poem) {
assertThat( poem ).isNotNull();
assertThat( poem.getId() ).as( "Wrong Id" ).isEqualTo( expectedPoem.getId() );
assertThat( poem.getName() ).as( "Wrong Name" ).isEqualTo( expectedPoem.getName() );
assertThat( poem.getAuthor() ).as( "Wrong Author" ).isEqualTo( expectedPoem.getAuthor() );
}
private void close(EntityManager em) {
em.clear();
em.close();
}
private EntityManager delete(Object... entities) {
for ( Object object : entities ) {
Object entity = em.merge( object );
em.remove( entity );
}
return em;
}
private void begin() throws Exception {
em.getTransaction().begin();
}
private void commit() throws Exception {
em.getTransaction().commit();
}
private void rollback() throws Exception {
em.getTransaction().rollback();
}
private EntityManager createEntityManager() {
return getFactory().createEntityManager();
}
}