/*
* 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.query.parsing.impl.predicate.impl;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.hql.ast.spi.predicate.ComparisonPredicate;
import org.hibernate.hql.ast.spi.predicate.ConjunctionPredicate;
import org.hibernate.hql.ast.spi.predicate.DisjunctionPredicate;
import org.hibernate.hql.ast.spi.predicate.InPredicate;
import org.hibernate.hql.ast.spi.predicate.IsNullPredicate;
import org.hibernate.hql.ast.spi.predicate.LikePredicate;
import org.hibernate.hql.ast.spi.predicate.NegationPredicate;
import org.hibernate.hql.ast.spi.predicate.PredicateFactory;
import org.hibernate.hql.ast.spi.predicate.RangePredicate;
import org.hibernate.hql.ast.spi.predicate.RootPredicate;
import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.Neo4jAliasResolver;
import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.Neo4jPropertyHelper;
import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.Neo4jQueryParameter;
import org.hibernate.ogm.datastore.neo4j.query.parsing.impl.PropertyIdentifier;
/**
* @author Davide D'Alto <davide@hibernate.org>
* @author Guillaume Smet
*/
public class Neo4jPredicateFactory implements PredicateFactory<StringBuilder> {
private final Neo4jPropertyHelper propertyHelper;
private final StringBuilder builder;
public Neo4jPredicateFactory(Neo4jPropertyHelper propertyHelper) {
this.propertyHelper = propertyHelper;
this.builder = new StringBuilder();
}
@Override
public RootPredicate<StringBuilder> getRootPredicate(String entityType) {
return new Neo4jRootPredicate();
}
@Override
public ComparisonPredicate<StringBuilder> getComparisonPredicate(String entityType, ComparisonPredicate.Type comparisonType,
List<String> propertyPath, Object value) {
Object neo4jValue = value instanceof Neo4jQueryParameter ? value : propertyHelper.convertToBackendType( entityType, propertyPath, value );
PropertyIdentifier columnIdentifier = getPropertyIdentifier( entityType, propertyPath );
return new Neo4jComparisonPredicate( builder, columnIdentifier.getAlias(), columnIdentifier.getPropertyName(), comparisonType, neo4jValue );
}
@Override
public DisjunctionPredicate<StringBuilder> getDisjunctionPredicate() {
return new Neo4jDisjunctionPredicate( builder );
}
@Override
public ConjunctionPredicate<StringBuilder> getConjunctionPredicate() {
return new Neo4jConjunctionPredicate( builder );
}
@Override
public InPredicate<StringBuilder> getInPredicate(String entityType, List<String> propertyPath, List<Object> typedElements) {
PropertyIdentifier columnIdentifier = getPropertyIdentifier( entityType, propertyPath );
List<Object> gridTypedElements = new ArrayList<Object>( typedElements.size() );
for ( Object typedElement : typedElements ) {
gridTypedElements.add( propertyHelper.convertToBackendType( entityType, propertyPath, typedElement ) );
}
return new Neo4jInPredicate( builder, columnIdentifier.getAlias(), columnIdentifier.getPropertyName(), gridTypedElements );
}
@Override
public RangePredicate<StringBuilder> getRangePredicate(String entityType, List<String> propertyPath, Object lowerValue, Object upperValue) {
PropertyIdentifier columnIdentifier = getPropertyIdentifier( entityType, propertyPath );
Object neo4jLowerValue = lowerValue instanceof Neo4jQueryParameter ? lowerValue : propertyHelper.convertToBackendType( entityType, propertyPath, lowerValue );
Object neo4jUpperValue = upperValue instanceof Neo4jQueryParameter ? upperValue : propertyHelper.convertToBackendType( entityType, propertyPath, upperValue );
return new Neo4jRangePredicate( builder, columnIdentifier.getAlias(), columnIdentifier.getPropertyName(), neo4jLowerValue, neo4jUpperValue );
}
@Override
public NegationPredicate<StringBuilder> getNegationPredicate() {
return new Neo4jNegationPredicate( builder );
}
@Override
public LikePredicate<StringBuilder> getLikePredicate(String entityType, List<String> propertyPath, String patternValue, Character escapeCharacter) {
PropertyIdentifier columnIdentifier = getPropertyIdentifier( entityType, propertyPath );
return new Neo4jLikePredicate( builder, columnIdentifier.getAlias(), columnIdentifier.getPropertyName(), patternValue, escapeCharacter );
}
@Override
public IsNullPredicate<StringBuilder> getIsNullPredicate(String entityType, List<String> propertyPath) {
PropertyIdentifier columnIdentifier = getPropertyIdentifier( entityType, propertyPath );
return new Neo4jIsNullPredicate( builder, columnIdentifier.getAlias(), columnIdentifier.getPropertyName() );
}
/**
* Returns the {@link PropertyIdentifier} corresponding to this property based on information provided by the {@link Neo4jAliasResolver}.
*
* Note that all the path is required as in the current implementation, the WHERE clause is appended before the OPTIONAL MATCH clauses
* so we need all the aliases referenced in the predicates in the MATCH clause. While it's definitely a limitation of the current implementation
* it's not really easy to do differently because the OPTIONAL MATCH clauses have to be executed on the filtered nodes and relationships
* and we don't have an easy way to know which predicates we should include in the MATCH clause.
*
* @param entityType the type of the entity
* @param propertyPath the path to the property without aliases
* @return the corresponding {@link PropertyIdentifier}
*/
private PropertyIdentifier getPropertyIdentifier(String entityType, List<String> propertyPath) {
return propertyHelper.getPropertyIdentifier( entityType, propertyPath, propertyPath.size() );
}
}