/* * 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.neo4j.test.query.parsing; import static org.fest.assertions.Assertions.assertThat; import java.util.HashMap; import java.util.Map; import org.hibernate.hql.QueryParser; import org.hibernate.hql.ast.spi.EntityNamesResolver; import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.Neo4jProcessingChain; import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.Neo4jQueryParsingResult; import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.Neo4jQueryRendererDelegate; import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.Neo4jQueryResolverDelegate; import org.hibernate.ogm.datastore.neo4j.test.query.parsing.model.IndexedEntity; import org.hibernate.ogm.datastore.neo4j.test.query.parsing.model.inheritance.CommunityMemberST; import org.hibernate.ogm.datastore.neo4j.test.query.parsing.model.inheritance.EmployeeST; import org.hibernate.ogm.datastore.neo4j.test.query.parsing.model.inheritance.PersonST; import org.hibernate.ogm.utils.OgmTestCase; import org.hibernate.ogm.utils.parser.MapBasedEntityNamesResolver; import org.junit.Before; import org.junit.Test; /** * Integration test for {@link Neo4jQueryRendererDelegate} and {@link Neo4jQueryResolverDelegate}. * * @author Davide D'Alto */ public class CypherQueryParsingTest extends OgmTestCase { private QueryParser queryParser; @Before public void setupParser() { queryParser = new QueryParser(); } @Test public void shouldCreateUnrestrictedQuery() { assertQuery( "from IndexedEntity", "MATCH (`<gen:0>`:IndexedEntity) RETURN `<gen:0>`" ); } @Test public void shouldCreateQueryWithSingleDiscriminatorValue() { assertQuery( "from EmployeeST", "MATCH (`<gen:0>`:PersonST) WHERE `<gen:0>`.DTYPE = \"EMP\" RETURN `<gen:0>`", EmployeeST.class ); } @Test public void shouldCreateQueryWithSingleDiscriminatorValueWithFilter() { assertQuery( "from EmployeeST e where e.employer = 'Red Hat'", "MATCH (e:PersonST) WHERE e.employer = \"Red Hat\" AND e.DTYPE = \"EMP\" RETURN e", EmployeeST.class ); } @Test public void shouldCreateQueryWithMultipleDiscriminatorValues() { assertQuery( "from CommunityMemberST", "MATCH (`<gen:0>`:PersonST) WHERE `<gen:0>`.DTYPE IN [\"EMP\", \"CMM\"] RETURN `<gen:0>`", CommunityMemberST.class ); } @Test public void shouldCreateQueryWithMultipleDiscriminatorValuesWithFilter() { assertQuery( "from CommunityMemberST c where c.project = 'Hibernate OGM'", "MATCH (c:PersonST) WHERE c.project = \"Hibernate OGM\" AND c.DTYPE IN [\"EMP\", \"CMM\"] RETURN c", CommunityMemberST.class ); } @Test public void shouldCreateRestrictedQueryUsingSelect() { assertQuery( "select e from IndexedEntity e where e.title = 'same'", "MATCH (e:IndexedEntity) WHERE e.title = \"same\" RETURN e" ); } @Test public void shouldUseSpecialNameForIdPropertyInWhereClause() { assertQuery( "select e from IndexedEntity e where e.id = '1'", "MATCH (e:IndexedEntity) WHERE e.id = \"1\" RETURN e" ); } @Test public void shouldUseColumnNameForPropertyInWhereClause() { assertQuery( "select e from IndexedEntity e where e.name = 'Bob'", "MATCH (e:IndexedEntity) WHERE e.entityName = \"Bob\" RETURN e" ); } @Test public void shouldCreateProjectionQuery() { Neo4jQueryParsingResult parsingResult = parseQuery( "select e.id, e.name, e.position from IndexedEntity e" ); assertThat( parsingResult.getQueryObject() ).isEqualTo( "MATCH (e:IndexedEntity) RETURN e.id, e.entityName, e.position" ); assertThat( parsingResult.getProjections() ).containsExactly( "e.id", "e.entityName", "e.position" ); } @Test public void shouldAddNumberPropertyAsNumber() { assertQuery( "select e from IndexedEntity e where e.position = 2", "MATCH (e:IndexedEntity) WHERE e.position = 2 RETURN e" ); } @Test public void shouldCreateLessOrEqualQuery() { assertQuery( "select e from IndexedEntity e where e.position <= 20", "MATCH (e:IndexedEntity) WHERE e.position <= 20 RETURN e" ); } @Test public void shouldCreateQueryWithNegationInWhereClause() { assertQuery( "select e from IndexedEntity e where e.name <> 'Bob'", "MATCH (e:IndexedEntity) WHERE e.entityName <> \"Bob\" RETURN e" ); } @Test public void shouldCreateQueryWithNestedNegationInWhereClause() { assertQuery( "select e from IndexedEntity e where NOT e.name <> 'Bob'", "MATCH (e:IndexedEntity) WHERE e.entityName = \"Bob\" RETURN e" ); } @Test public void shouldCreateQueryUsingSelectWithConjunctionInWhereClause() { assertQuery( "select e from IndexedEntity e where e.title = 'same' and e.position = 1", "MATCH (e:IndexedEntity) WHERE (e.title = \"same\") AND (e.position = 1) RETURN e" ); } @Test public void shouldCreateQueryWithNegationAndConjunctionInWhereClause() { assertQuery( "select e from IndexedEntity e where NOT ( e.name = 'Bob' AND e.position = 1 )", "MATCH (e:IndexedEntity) WHERE (e.entityName <> \"Bob\") OR (e.position <> 1) RETURN e" ); } @Test public void shouldCreateNegatedRangeQuery() { assertQuery( "select e from IndexedEntity e where e.name = 'Bob' and not e.position between 1 and 3", "MATCH (e:IndexedEntity) WHERE (e.entityName = \"Bob\") AND (e.position < 1 OR e.position > 3) RETURN e" ); } @Test public void shouldCreateBooleanQueryUsingSelect() { assertQuery( "select e from IndexedEntity e where e.name = 'same' or ( e.id = 4 and e.name = 'booh')", "MATCH (e:IndexedEntity) WHERE (e.entityName = \"same\") OR ((e.id = \"4\") AND (e.entityName = \"booh\")) RETURN e" ); } @Test public void shouldCreateNumericBetweenQuery() { Map<String, Object> namedParameters = new HashMap<String, Object>(); namedParameters.put( "lower", 10L ); namedParameters.put( "upper", 20L ); assertQuery( "select e from IndexedEntity e where e.position between :lower and :upper", namedParameters, "MATCH (e:IndexedEntity) WHERE e.position >= {lower} AND e.position <= {upper} RETURN e" ); } @Test public void shouldCreateInQuery() { assertQuery( "select e from IndexedEntity e where e.title IN ( 'foo', 'bar', 'same')", "MATCH (e:IndexedEntity) WHERE ANY( _x_ IN [\"foo\", \"bar\", \"same\"] WHERE e.title = _x_) RETURN e" ); } @Test public void shouldCreateNotInQuery() { assertQuery( "select e from IndexedEntity e where e.title NOT IN ( 'foo', 'bar', 'same')", "MATCH (e:IndexedEntity) WHERE NOT EXISTS(e.title) OR NONE( _x_ IN [\"foo\", \"bar\", \"same\"] WHERE e.title = _x_) RETURN e" ); } @Test public void shouldCreateLikeQuery() { assertQuery( "select e from IndexedEntity e where e.title like 'Ali_e%'", "MATCH (e:IndexedEntity) WHERE e.title=~\"^\\\\QAli\\\\E.\\\\Qe\\\\E.*$\" RETURN e" ); } @Test public void shouldCreateNotLikeQuery() { assertQuery( "select e from IndexedEntity e where e.title not like 'Ali_e%'", "MATCH (e:IndexedEntity) WHERE NOT EXISTS(e.title) OR NOT(e.title=~\"^\\\\QAli\\\\E.\\\\Qe\\\\E.*$\") RETURN e" ); } @Test public void shouldCreateIsNullQuery() { assertQuery( "select e from IndexedEntity e where e.title is null", "MATCH (e:IndexedEntity) WHERE NOT EXISTS(e.title) RETURN e" ); } @Test public void shouldCreateIsNotNullQuery() { assertQuery( "select e from IndexedEntity e where e.title is not null", "MATCH (e:IndexedEntity) WHERE EXISTS(e.title) RETURN e" ); } private void assertQuery(String hqlQuery, String expectedQuery) { assertQuery( hqlQuery, null, expectedQuery ); } private void assertQuery(String hqlQuery, String expectedMongoDbQuery, Class<?> expectedEntityType) { assertQuery( hqlQuery, null, expectedMongoDbQuery, expectedEntityType ); } private void assertQuery(String hqlQuery, Map<String, Object> namedParameters, String expectedQuery) { assertQuery( hqlQuery, namedParameters, expectedQuery, IndexedEntity.class ); } private void assertQuery(String queryString, Map<String, Object> namedParameters, String expectedQuery, Class<?> expectedEntityType) { Neo4jQueryParsingResult parsingResult = parseQuery( queryString, namedParameters ); assertThat( parsingResult ).isNotNull(); assertThat( parsingResult.getEntityType() ).isSameAs( expectedEntityType ); if ( expectedQuery == null ) { assertThat( parsingResult.getQueryObject() ).isNull(); } else { assertThat( parsingResult.getQueryObject() ).isNotNull(); assertThat( parsingResult.getQueryObject() ).isEqualTo( expectedQuery ); } } private Neo4jQueryParsingResult parseQuery(String queryString) { return parseQuery( queryString, null ); } private Neo4jQueryParsingResult parseQuery(String queryString, Map<String, Object> namedParameters) { return queryParser.parseQuery( queryString, setUpProcessingChain( namedParameters ) ); } private Neo4jProcessingChain setUpProcessingChain(Map<String, Object> namedParameters) { Map<String, Class<?>> entityNames = new HashMap<String, Class<?>>(); entityNames.put( "com.acme.IndexedEntity", IndexedEntity.class ); entityNames.put( "IndexedEntity", IndexedEntity.class ); entityNames.put( "CommunityMemberST", CommunityMemberST.class ); entityNames.put( "PersonST", PersonST.class ); entityNames.put( "EmployeeST", EmployeeST.class ); EntityNamesResolver nameResolver = new MapBasedEntityNamesResolver( entityNames ); return new Neo4jProcessingChain( getSessionFactory(), nameResolver, namedParameters ); } @Override protected Class<?>[] getAnnotatedClasses() { return new Class<?>[]{ IndexedEntity.class, PersonST.class, CommunityMemberST.class, EmployeeST.class }; } }