diff --git a/pom.xml b/pom.xml index 4769ffd..c1d7d3f 100644 --- a/pom.xml +++ b/pom.xml @@ -2,9 +2,9 @@ 4.0.0 - com.github.tennaito + br.com.elotech rsql-jpa - 2.0.3-SNAPSHOT + 2.0.4-SNAPSHOT jar @@ -30,15 +30,16 @@ - https://github.com/tennaito/rsql-jpa/ - scm:git:https://github.com/tennaito/rsql-jpa.git - scm:git:https://github.com/tennaito/rsql-jpa.git - HEAD + https://github.com/Elotech-Dev/rsql-jpa.git + scm:git:https://github.com/Elotech-Dev/rsql-jpa.git + scm:git:https://github.com/Elotech-Dev/rsql-jpa.git + 2.0.3 + -Xdoclint:none UTF-8 @@ -112,8 +113,8 @@ 1.6.3 true - ossrh - https://oss.sonatype.org/ + nexus + https://nexus.elotech.com.br/ false @@ -142,20 +143,9 @@ - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - - sign-artifacts - verify - - sign - - - + + -Xdoclint:none + @@ -267,20 +257,12 @@ - ossrh - https://oss.sonatype.org/content/repositories/snapshots + nexus + http://nexus.elotech.com.br/repository/snapshots/ - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + nexus + http://nexus.elotech.com.br/repository/releases/ - - - travis - https://travis-ci.org/tennaito/rsql-jpa - - - GitHub - https://github.com/tennaito/rsql-jpa/issues - + diff --git a/src/main/java/com/github/tennaito/rsql/jpa/PredicateBuilder.java b/src/main/java/com/github/tennaito/rsql/jpa/PredicateBuilder.java index 01b7c89..e2aa518 100755 --- a/src/main/java/com/github/tennaito/rsql/jpa/PredicateBuilder.java +++ b/src/main/java/com/github/tennaito/rsql/jpa/PredicateBuilder.java @@ -24,12 +24,15 @@ */ package com.github.tennaito.rsql.jpa; -import com.github.tennaito.rsql.builder.BuilderTools; -import com.github.tennaito.rsql.parser.ast.ComparisonOperatorProxy; -import cz.jirutka.rsql.parser.ast.ComparisonNode; -import cz.jirutka.rsql.parser.ast.ComparisonOperator; -import cz.jirutka.rsql.parser.ast.LogicalNode; -import cz.jirutka.rsql.parser.ast.Node; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; @@ -43,13 +46,14 @@ import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; import javax.persistence.metamodel.PluralAttribute; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; + +import com.github.tennaito.rsql.builder.BuilderTools; +import com.github.tennaito.rsql.parser.ast.ComparisonOperatorProxy; + +import cz.jirutka.rsql.parser.ast.ComparisonNode; +import cz.jirutka.rsql.parser.ast.ComparisonOperator; +import cz.jirutka.rsql.parser.ast.LogicalNode; +import cz.jirutka.rsql.parser.ast.Node; /** * PredicateBuilder @@ -58,7 +62,8 @@ * * @author AntonioRabelo * - * Based from CriterionBuilders of rsql-hibernate created by Jakub Jirutka . + * Based from CriterionBuilders of rsql-hibernate created by Jakub + * Jirutka . * * @since 2015-02-05 */ @@ -66,590 +71,716 @@ public final class PredicateBuilder { private static final Logger LOG = Logger.getLogger(PredicateBuilder.class.getName()); - public static final Character LIKE_WILDCARD = '*'; - - private static final Date START_DATE; - private static final Date END_DATE; - - static { - // - // Use a date range that Oracle can cope with - apparently the years around 1 BC and 1 AD are messed up in Oracle - known bug - // - Calendar cal = Calendar.getInstance(); - cal.set( 9999, Calendar.DECEMBER, 31); - END_DATE = cal.getTime(); - cal.set( 5, Calendar.JANUARY, 1); // Use Jan 1, 5 AD, since that's where the Roman's sort of got it together with leap years. - START_DATE = cal.getTime(); - } - - /** - * Private constructor. - */ - private PredicateBuilder(){ - super(); - } - - /** - * Create a Predicate from the RSQL AST node. - * - * @param node RSQL AST node. - * @param root From that predicate expression paths depends on. - * @param entity The main entity of the query. - * @param manager JPA EntityManager. - * @param misc Facade with all necessary tools for predicate creation. - * @return Predicate a predicate representation of the Node. - */ - public static Predicate createPredicate(Node node, From root, Class entity, EntityManager manager, BuilderTools misc) { - LOG.log(Level.INFO, "Creating Predicate for: {0}", node); - - if (node instanceof LogicalNode) { - return createPredicate((LogicalNode)node, root, entity, manager, misc); - } - - if (node instanceof ComparisonNode) { - return createPredicate((ComparisonNode)node, root, entity, manager, misc); - } - - throw new IllegalArgumentException("Unknown expression type: " + node.getClass()); - } - - /** - * Create a Predicate from the RSQL AST logical node. - * - * @param logical RSQL AST logical node. - * @param root From that predicate expression paths depends on. - * @param entity The main entity of the query. - * @param entityManager JPA EntityManager. - * @param misc Facade with all necessary tools for predicate creation. - * @return Predicate a predicate representation of the Node. - */ - public static Predicate createPredicate(LogicalNode logical, From root, Class entity, EntityManager entityManager, BuilderTools misc) { - LOG.log(Level.INFO, "Creating Predicate for logical node: {0}", logical); - - CriteriaBuilder builder = entityManager.getCriteriaBuilder(); - - List predicates = new ArrayList(); - - LOG.log(Level.INFO, "Creating Predicates from all children nodes."); - for (Node node : logical.getChildren()) { - predicates.add(createPredicate(node, root, entity, entityManager, misc)); + public static final Character LIKE_WILDCARD = '*'; + + private static final Date START_DATE; + private static final Date END_DATE; + + static { + // + // Use a date range that Oracle can cope with - apparently the years + // around 1 BC and 1 AD are messed up in Oracle - known bug + // + Calendar cal = Calendar.getInstance(); + cal.set(9999, Calendar.DECEMBER, 31); + END_DATE = cal.getTime(); + cal.set(5, Calendar.JANUARY, 1); // Use Jan 1, 5 AD, since that's where + // the Roman's sort of got it together + // with leap years. + START_DATE = cal.getTime(); + } + + /** + * Private constructor. + */ + private PredicateBuilder() { + super(); + } + + /** + * Create a Predicate from the RSQL AST node. + * + * @param node + * RSQL AST node. + * @param root + * From that predicate expression paths depends on. + * @param entity + * The main entity of the query. + * @param manager + * JPA EntityManager. + * @param misc + * Facade with all necessary tools for predicate creation. + * @return Predicate a predicate representation of the Node. + */ + public static Predicate createPredicate(Node node, From root, Class entity, EntityManager manager, + BuilderTools misc) { + LOG.log(Level.INFO, "Creating Predicate for: {0}", node); + + if (node instanceof LogicalNode) { + return createPredicate((LogicalNode) node, root, entity, manager, misc); + } + + if (node instanceof ComparisonNode) { + return createPredicate((ComparisonNode) node, root, entity, manager, misc); + } + + throw new IllegalArgumentException("Unknown expression type: " + node.getClass()); + } + + /** + * Create a Predicate from the RSQL AST logical node. + * + * @param logical + * RSQL AST logical node. + * @param root + * From that predicate expression paths depends on. + * @param entity + * The main entity of the query. + * @param entityManager + * JPA EntityManager. + * @param misc + * Facade with all necessary tools for predicate creation. + * @return Predicate a predicate representation of the Node. + */ + public static Predicate createPredicate(LogicalNode logical, From root, Class entity, + EntityManager entityManager, BuilderTools misc) { + LOG.log(Level.INFO, "Creating Predicate for logical node: {0}", logical); + + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + + List predicates = new ArrayList(); + + LOG.log(Level.INFO, "Creating Predicates from all children nodes."); + for (Node node : logical.getChildren()) { + predicates.add(createPredicate(node, root, entity, entityManager, misc)); + } + + switch (logical.getOperator()) { + case AND: + return builder.and(predicates.toArray(new Predicate[predicates.size()])); + case OR: + return builder.or(predicates.toArray(new Predicate[predicates.size()])); } - switch (logical.getOperator()) { - case AND : return builder.and(predicates.toArray(new Predicate[predicates.size()])); - case OR : return builder.or(predicates.toArray(new Predicate[predicates.size()])); - } - - throw new IllegalArgumentException("Unknown operator: " + logical.getOperator()); - } - - /** - * Create a Predicate from the RSQL AST comparison node. - * - * @param comparison RSQL AST comparison node. - * @param startRoot From that predicate expression paths depends on. - * @param entity The main entity of the query. - * @param entityManager JPA EntityManager. - * @param misc Facade with all necessary tools for predicate creation. - * @return Predicate a predicate representation of the Node. - */ - public static Predicate createPredicate(ComparisonNode comparison, From startRoot, Class entity, EntityManager entityManager, BuilderTools misc) { - if (startRoot == null) { - String msg = "From root node was undefined."; - LOG.log(Level.SEVERE, msg); - throw new IllegalArgumentException(msg); - } - LOG.log(Level.INFO, "Creating Predicate for comparison node: {0}", comparison); - - LOG.log(Level.INFO, "Property graph path : {0}", comparison.getSelector()); - Expression propertyPath = findPropertyPath(comparison.getSelector(), startRoot, entityManager, misc); + throw new IllegalArgumentException("Unknown operator: " + logical.getOperator()); + } + + /** + * Create a Predicate from the RSQL AST comparison node. + * + * @param comparison + * RSQL AST comparison node. + * @param startRoot + * From that predicate expression paths depends on. + * @param entity + * The main entity of the query. + * @param entityManager + * JPA EntityManager. + * @param misc + * Facade with all necessary tools for predicate creation. + * @return Predicate a predicate representation of the Node. + */ + public static Predicate createPredicate(ComparisonNode comparison, From startRoot, Class entity, + EntityManager entityManager, BuilderTools misc) { + if (startRoot == null) { + String msg = "From root node was undefined."; + LOG.log(Level.SEVERE, msg); + throw new IllegalArgumentException(msg); + } + LOG.log(Level.INFO, "Creating Predicate for comparison node: {0}", comparison); + + LOG.log(Level.INFO, "Property graph path : {0}", comparison.getSelector()); + Expression propertyPath = findPropertyPath(comparison.getSelector(), startRoot, entityManager, misc); LOG.log(Level.INFO, "Cast all arguments to type {0}.", propertyPath.getJavaType().getName()); - List castedArguments = misc.getArgumentParser().parse(comparison.getArguments(), propertyPath.getJavaType()); - - try { - // try to create a predicate - return PredicateBuilder.createPredicate(propertyPath, comparison.getOperator(), castedArguments, entityManager); - } catch (IllegalArgumentException e) { - // if operator dont exist try to delegate - if (misc.getPredicateBuilder() != null) { - return misc.getPredicateBuilder().createPredicate(comparison, startRoot, entity, entityManager, misc); - } - // if no strategy was defined then there are no more operators. - throw e; - } - } - - /** - * Find a property path in the graph from startRoot - * - * @param propertyPath The property path to find. - * @param startRoot From that property path depends on. - * @param entityManager JPA EntityManager. - * @param misc Facade with all necessary tools for predicate creation. - * @return The Path for the property path - * @throws IllegalArgumentException if attribute of the given property name does not exist - */ - public static Path findPropertyPath(String propertyPath, Path startRoot, EntityManager entityManager, BuilderTools misc) { - String[] graph = propertyPath.split("\\."); - - Metamodel metaModel = entityManager.getMetamodel(); - ManagedType classMetadata = metaModel.managedType(startRoot.getJavaType()); - - Path root = startRoot; - - for (String property : graph) { - String mappedProperty = misc.getPropertiesMapper().translate(property, classMetadata.getJavaType()); - if( !mappedProperty.equals( property) ) { - root = findPropertyPath( mappedProperty, root, entityManager, misc ); - } else { - if (!hasPropertyName(mappedProperty, classMetadata)) { - throw new IllegalArgumentException("Unknown property: " + mappedProperty + " from entity " + classMetadata.getJavaType().getName()); - } - - if (isAssociationType(mappedProperty, classMetadata)) { - Class associationType = findPropertyType(mappedProperty, classMetadata); - String previousClass = classMetadata.getJavaType().getName(); - classMetadata = metaModel.managedType(associationType); - LOG.log(Level.INFO, "Create a join between {0} and {1}.", new Object[]{previousClass, classMetadata.getJavaType().getName()}); - - if (root instanceof Join) { - root = root.get(mappedProperty); - } else { - root = ((From) root).join(mappedProperty); - } - } else { - LOG.log(Level.INFO, "Create property path for type {0} property {1}.", new Object[]{classMetadata.getJavaType().getName(), mappedProperty}); - root = root.get(mappedProperty); - - if (isEmbeddedType(mappedProperty, classMetadata)) { - Class embeddedType = findPropertyType(mappedProperty, classMetadata); - classMetadata = metaModel.managedType(embeddedType); - } - } - } - } - - return root; - } - - /////////////// TEMPLATE METHODS /////////////// - - /** - * Create Predicate for comparison operators. - * - * @param propertyPath Property path that we want to compare. - * @param operator Comparison operator. - * @param arguments Arguments (1 for binary comparisons, n for multi-value comparisons [in, not in (out)]) - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createPredicate(Expression propertyPath, ComparisonOperator operator, List arguments, EntityManager manager) { - LOG.log(Level.INFO, "Creating predicate: propertyPath {0} {1}", new Object[]{operator, arguments}); - - if (ComparisonOperatorProxy.asEnum(operator) != null) { - switch (ComparisonOperatorProxy.asEnum(operator)) { - case EQUAL : { - Object argument = arguments.get(0); - if (argument instanceof String) { - return createLike(propertyPath, (String) argument, manager); - } else if (isNullArgument(argument)) { - return createIsNull(propertyPath, manager); - } else { - return createEqual(propertyPath, argument, manager); - } - } - case NOT_EQUAL : { - Object argument = arguments.get(0); - if (argument instanceof String) { - return createNotLike(propertyPath, (String) argument, manager); - } else if (isNullArgument(argument)) { - return createIsNotNull(propertyPath, manager); - } else { - return createNotEqual(propertyPath, argument, manager); - } - } - case GREATER_THAN : { - Object argument = arguments.get(0); - Predicate predicate; - if (argument instanceof Date) { - int days = 1; - predicate = createBetweenThan(propertyPath, modifyDate(argument, days), END_DATE, manager); - } else if (argument instanceof Number || argument == null) { - predicate = createGreaterThan(propertyPath, (Number) argument, manager); - } else if (argument instanceof Comparable) { - predicate = createGreaterThanComparable(propertyPath, (Comparable) argument, manager); - } else { - throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); - } - return predicate; - } - case GREATER_THAN_OR_EQUAL : { - Object argument = arguments.get(0); - Predicate predicate; - if (argument instanceof Date){ - predicate = createBetweenThan(propertyPath, (Date)argument, END_DATE, manager); - } else if (argument instanceof Number || argument == null) { - predicate = createGreaterEqual(propertyPath, (Number)argument, manager); - } else if (argument instanceof Comparable) { - predicate = createGreaterEqualComparable(propertyPath, (Comparable) argument, manager); - } else { - throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); - } - return predicate; - - } - case LESS_THAN : { - Object argument = arguments.get(0); - Predicate predicate; - if (argument instanceof Date) { - int days = -1; - predicate = createBetweenThan(propertyPath, START_DATE, modifyDate(argument, days), manager); - } else if (argument instanceof Number || argument == null) { - predicate = createLessThan(propertyPath, (Number) argument, manager); - } else if (argument instanceof Comparable) { - predicate = createLessThanComparable(propertyPath, (Comparable) argument, manager); - } else { - throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); - } - return predicate; - } - case LESS_THAN_OR_EQUAL : { - Object argument = arguments.get(0); - - Predicate predicate; - if (argument instanceof Date){ - predicate = createBetweenThan(propertyPath,START_DATE, (Date)argument, manager); - } else if (argument instanceof Number || argument == null) { - predicate = createLessEqual(propertyPath, (Number)argument, manager); - } else if (argument instanceof Comparable) { - predicate = createLessEqualComparable(propertyPath, (Comparable) argument, manager); - } else { - throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); - } - return predicate; - } - case IN : return createIn(propertyPath, arguments, manager); - case NOT_IN : return createNotIn(propertyPath, arguments, manager); - } - } - throw new IllegalArgumentException("Unknown operator: " + operator); - } - - /** - + * Creates the between than. - + * - + * @param propertyPath the property path - + * @param startDate the start date - + * @param argument the argument - + * @param manager the manager - + * @return the predicate - + */ - private static Predicate createBetweenThan(Expression propertyPath, Date start, Date end, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.between(propertyPath, start, end); - } - - /** - * Apply a case-insensitive "like" constraint to the property path. Value - * should contains wildcards "*" (% in SQL) and "_". - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument with/without wildcards - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createLike(Expression propertyPath, String argument, EntityManager manager) { - String like = argument.replace(LIKE_WILDCARD, '%'); - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.like(builder.lower(propertyPath), like.toLowerCase()); - } - - /** - * Apply an "is null" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createIsNull(Expression propertyPath, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.isNull(propertyPath); - } - - /** - * Apply an "equal" constraint to property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createEqual(Expression propertyPath, Object argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.equal(propertyPath, argument); - } - - /** - * Apply a "not equal" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createNotEqual(Expression propertyPath, Object argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.notEqual(propertyPath, argument); - } - - /** - * Apply a negative case-insensitive "like" constraint to the property path. - * Value should contains wildcards "*" (% in SQL) and "_". - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument with/without wildcards - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createNotLike(Expression propertyPath, String argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.not(createLike(propertyPath, argument, manager)); - } - - /** - * Apply an "is not null" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createIsNotNull(Expression propertyPath, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.isNotNull(propertyPath); - } - - /** - * Apply a "greater than" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument number. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createGreaterThan(Expression propertyPath, Number argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.gt(propertyPath, argument); - } - - /** - * Apply a "greater than" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static > Predicate createGreaterThanComparable(Expression propertyPath, Y argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.greaterThan(propertyPath, argument); - } - - /** - * Apply a "greater than or equal" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument number. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createGreaterEqual(Expression propertyPath, Number argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.ge(propertyPath, argument); - } - - /** - * Apply a "greater than or equal" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static > Predicate createGreaterEqualComparable(Expression propertyPath, Y argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.greaterThanOrEqualTo(propertyPath, argument); - } - - /** - * Apply a "less than" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument number. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createLessThan(Expression propertyPath, Number argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.lt(propertyPath, argument); - } - - /** - * Apply a "less than" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static > Predicate createLessThanComparable(Expression propertyPath, Y argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.lessThan(propertyPath, argument); - } - - /** - * Apply a "less than or equal" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument number. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createLessEqual(Expression propertyPath, Number argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.le(propertyPath, argument); - } - - /** - * Apply a "less than or equal" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param argument Argument. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static > Predicate createLessEqualComparable(Expression propertyPath, Y argument, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.lessThanOrEqualTo(propertyPath, argument); - } - - /** - * Apply a "in" constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param arguments List of arguments. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createIn(Expression propertyPath, List arguments, EntityManager manager) { - return propertyPath.in(arguments); - } - - /** - * Apply a "not in" (out) constraint to the property path. - * - * @param propertyPath Property path that we want to compare. - * @param arguments List of arguments. - * @param manager JPA EntityManager. - * @return Predicate a predicate representation. - */ - private static Predicate createNotIn(Expression propertyPath, List arguments, EntityManager manager) { - CriteriaBuilder builder = manager.getCriteriaBuilder(); - return builder.not(createIn(propertyPath,arguments, manager)); - } - - /** - * Verify if a property is an Association type. - * - * @param property Property to verify. - * @param classMetadata Metamodel of the class we want to check. - * @return true if the property is an associantion, false otherwise. - */ - private static boolean isAssociationType(String property, ManagedType classMetadata){ - return classMetadata.getAttribute(property).isAssociation(); - } - - /** - * Verify if a property is an Embedded type. - * - * @param property Property to verify. - * @param classMetadata Metamodel of the class we want to check. - * @return true if the property is an embedded attribute, false otherwise. - */ - private static boolean isEmbeddedType(String property, ManagedType classMetadata){ - return classMetadata.getAttribute(property).getPersistentAttributeType() == PersistentAttributeType.EMBEDDED; - } - - /** - * Verifies if a class metamodel has the specified property. - * - * @param property Property name. - * @param classMetadata Class metamodel that may hold that property. - * @return true if the class has that property, false otherwise. - */ - private static boolean hasPropertyName(String property, ManagedType classMetadata) { - Set> names = classMetadata.getAttributes(); - for (Attribute name : names) { - if (name.getName().equals(property)) return true; - } - return false; - } - - /** - * Get the property Type out of the metamodel. - * - * @param property Property name for type extraction. - * @param classMetadata Reference class metamodel that holds property type. - * @return Class java type for the property, - * if the property is a pluralAttribute it will take the bindable java type of that collection. - */ - private static Class findPropertyType(String property, ManagedType classMetadata) { - Class propertyType = null; - if (classMetadata.getAttribute(property).isCollection()) { - propertyType = ((PluralAttribute)classMetadata.getAttribute(property)).getBindableJavaType(); - } else { - propertyType = classMetadata.getAttribute(property).getJavaType(); - } - return propertyType; - } - - /** - * Verifies if the argument is null. - * - * @param argument - * @return true if argument is null, false otherwise - */ - private static boolean isNullArgument(Object argument) { - return argument == null; - } - - - /** - * Get date regarding the operation (less then or greater than) - * - * @param argument Date to be modified - * @param days Days to be added or removed form argument; - *@return Date modified date - */ - private static Date modifyDate(Object argument, int days) { - Date date = (Date) argument; - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.add(Calendar.DATE, days); - date = c.getTime(); - return date; - } - - /** - * Builds an error message that reports that the argument is not suitable for use with the comparison operator. - * @param operator operator from the RSQL query - * @param argument actual argument produced from the ArgumentParser - * @return Error message for use in an Exception - */ - private static String buildNotComparableMessage(ComparisonOperator operator, Object argument) { - return String.format("Invalid type for comparison operator: %s type: %s must implement Comparable<%s>", - operator, - argument.getClass().getName(), - argument.getClass().getSimpleName()); - } + List castedArguments = misc.getArgumentParser().parse(comparison.getArguments(), + propertyPath.getJavaType()); + + try { + // try to create a predicate + return PredicateBuilder.createPredicate(propertyPath, comparison.getOperator(), castedArguments, + entityManager); + } catch (IllegalArgumentException e) { + // if operator dont exist try to delegate + if (misc.getPredicateBuilder() != null) { + return misc.getPredicateBuilder().createPredicate(comparison, startRoot, entity, entityManager, misc); + } + // if no strategy was defined then there are no more operators. + throw e; + } + } + + /** + * Find a property path in the graph from startRoot + * + * @param propertyPath + * The property path to find. + * @param startRoot + * From that property path depends on. + * @param entityManager + * JPA EntityManager. + * @param misc + * Facade with all necessary tools for predicate creation. + * @return The Path for the property path + * @throws IllegalArgumentException + * if attribute of the given property name does not exist + */ + public static Path findPropertyPath(String propertyPath, Path startRoot, EntityManager entityManager, + BuilderTools misc) { + String[] graph = propertyPath.split("\\."); + + Metamodel metaModel = entityManager.getMetamodel(); + ManagedType classMetadata = metaModel.managedType(startRoot.getJavaType()); + + Path root = startRoot; + + for (String property : graph) { + String mappedProperty = misc.getPropertiesMapper().translate(property, classMetadata.getJavaType()); + if (!mappedProperty.equals(property)) { + root = findPropertyPath(mappedProperty, root, entityManager, misc); + } else { + if (!hasPropertyName(mappedProperty, classMetadata)) { + throw new IllegalArgumentException("Unknown property: " + mappedProperty + " from entity " + + classMetadata.getJavaType().getName()); + } + + if (isAssociationType(mappedProperty, classMetadata)) { + Class associationType = findPropertyType(mappedProperty, classMetadata); + String previousClass = classMetadata.getJavaType().getName(); + classMetadata = metaModel.managedType(associationType); + LOG.log(Level.INFO, "Create a join between {0} and {1}.", + new Object[] { previousClass, classMetadata.getJavaType().getName() }); + + if (root instanceof From) { + + root = findJoin((From) root, mappedProperty); + + } else { + root = root.get(mappedProperty); + } + } else { + LOG.log(Level.INFO, "Create property path for type {0} property {1}.", + new Object[] { classMetadata.getJavaType().getName(), mappedProperty }); + + root = root.get(mappedProperty); + + if (isEmbeddedType(mappedProperty, classMetadata)) { + Class embeddedType = findPropertyType(mappedProperty, classMetadata); + classMetadata = metaModel.managedType(embeddedType); + } + } + } + } + + return root; + } + + private static Join findJoin(From rootFrom, String mappedProperty) { + + for (Join join : rootFrom.getJoins()) { + + if (join.getAttribute().getName().equals(mappedProperty)) { + + return join; + } + + } + + return rootFrom.join(mappedProperty); + + } + + /////////////// TEMPLATE METHODS /////////////// + + /** + * Create Predicate for comparison operators. + * + * @param propertyPath + * Property path that we want to compare. + * @param operator + * Comparison operator. + * @param arguments + * Arguments (1 for binary comparisons, n for multi-value comparisons + * [in, not in (out)]) + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createPredicate(Expression propertyPath, ComparisonOperator operator, + List arguments, EntityManager manager) { + LOG.log(Level.INFO, "Creating predicate: propertyPath {0} {1}", new Object[] { operator, arguments }); + + if (ComparisonOperatorProxy.asEnum(operator) != null) { + switch (ComparisonOperatorProxy.asEnum(operator)) { + case EQUAL: { + Object argument = arguments.get(0); + if (argument instanceof String) { + return createLike(propertyPath, (String) argument, manager); + } else if (isNullArgument(argument)) { + return createIsNull(propertyPath, manager); + } else { + return createEqual(propertyPath, argument, manager); + } + } + case NOT_EQUAL: { + Object argument = arguments.get(0); + if (argument instanceof String) { + return createNotLike(propertyPath, (String) argument, manager); + } else if (isNullArgument(argument)) { + return createIsNotNull(propertyPath, manager); + } else { + return createNotEqual(propertyPath, argument, manager); + } + } + case GREATER_THAN: { + Object argument = arguments.get(0); + Predicate predicate; + if (argument instanceof Date) { + int days = 1; + predicate = createBetweenThan(propertyPath, modifyDate(argument, days), END_DATE, manager); + } else if (argument instanceof Number || argument == null) { + predicate = createGreaterThan(propertyPath, (Number) argument, manager); + } else if (argument instanceof Comparable) { + predicate = createGreaterThanComparable(propertyPath, (Comparable) argument, manager); + } else { + throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); + } + return predicate; + } + case GREATER_THAN_OR_EQUAL: { + Object argument = arguments.get(0); + Predicate predicate; + if (argument instanceof Date) { + predicate = createBetweenThan(propertyPath, (Date) argument, END_DATE, manager); + } else if (argument instanceof Number || argument == null) { + predicate = createGreaterEqual(propertyPath, (Number) argument, manager); + } else if (argument instanceof Comparable) { + predicate = createGreaterEqualComparable(propertyPath, (Comparable) argument, manager); + } else { + throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); + } + return predicate; + + } + case LESS_THAN: { + Object argument = arguments.get(0); + Predicate predicate; + if (argument instanceof Date) { + int days = -1; + predicate = createBetweenThan(propertyPath, START_DATE, modifyDate(argument, days), manager); + } else if (argument instanceof Number || argument == null) { + predicate = createLessThan(propertyPath, (Number) argument, manager); + } else if (argument instanceof Comparable) { + predicate = createLessThanComparable(propertyPath, (Comparable) argument, manager); + } else { + throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); + } + return predicate; + } + case LESS_THAN_OR_EQUAL: { + Object argument = arguments.get(0); + + Predicate predicate; + if (argument instanceof Date) { + predicate = createBetweenThan(propertyPath, START_DATE, (Date) argument, manager); + } else if (argument instanceof Number || argument == null) { + predicate = createLessEqual(propertyPath, (Number) argument, manager); + } else if (argument instanceof Comparable) { + predicate = createLessEqualComparable(propertyPath, (Comparable) argument, manager); + } else { + throw new IllegalArgumentException(buildNotComparableMessage(operator, argument)); + } + return predicate; + } + case IN: + return createIn(propertyPath, arguments, manager); + case NOT_IN: + return createNotIn(propertyPath, arguments, manager); + } + } + throw new IllegalArgumentException("Unknown operator: " + operator); + } + + /** + * + * Creates the between than. + * + * @param propertyPath the property path + + * * @param startDate the start date + * @param argument the argument + * @param + * manager the manager + * @return the predicate + + */ + private static Predicate createBetweenThan(Expression propertyPath, Date start, Date end, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.between(propertyPath, start, end); + } + + /** + * Apply a case-insensitive "like" constraint to the property path. Value should + * contains wildcards "*" (% in SQL) and "_". + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument with/without wildcards + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createLike(Expression propertyPath, String argument, EntityManager manager) { + String like = argument.replace(LIKE_WILDCARD, '%'); + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.like(builder.lower(propertyPath), like.toLowerCase()); + } + + /** + * Apply an "is null" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createIsNull(Expression propertyPath, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.isNull(propertyPath); + } + + /** + * Apply an "equal" constraint to property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createEqual(Expression propertyPath, Object argument, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.equal(propertyPath, argument); + } + + /** + * Apply a "not equal" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createNotEqual(Expression propertyPath, Object argument, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.notEqual(propertyPath, argument); + } + + /** + * Apply a negative case-insensitive "like" constraint to the property path. + * Value should contains wildcards "*" (% in SQL) and "_". + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument with/without wildcards + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createNotLike(Expression propertyPath, String argument, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.not(createLike(propertyPath, argument, manager)); + } + + /** + * Apply an "is not null" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createIsNotNull(Expression propertyPath, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.isNotNull(propertyPath); + } + + /** + * Apply a "greater than" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument number. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createGreaterThan(Expression propertyPath, Number argument, + EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.gt(propertyPath, argument); + } + + /** + * Apply a "greater than" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static > Predicate createGreaterThanComparable( + Expression propertyPath, Y argument, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.greaterThan(propertyPath, argument); + } + + /** + * Apply a "greater than or equal" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument number. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createGreaterEqual(Expression propertyPath, Number argument, + EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.ge(propertyPath, argument); + } + + /** + * Apply a "greater than or equal" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static > Predicate createGreaterEqualComparable( + Expression propertyPath, Y argument, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.greaterThanOrEqualTo(propertyPath, argument); + } + + /** + * Apply a "less than" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument number. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createLessThan(Expression propertyPath, Number argument, + EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.lt(propertyPath, argument); + } + + /** + * Apply a "less than" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static > Predicate createLessThanComparable( + Expression propertyPath, Y argument, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.lessThan(propertyPath, argument); + } + + /** + * Apply a "less than or equal" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument number. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createLessEqual(Expression propertyPath, Number argument, + EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.le(propertyPath, argument); + } + + /** + * Apply a "less than or equal" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param argument + * Argument. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static > Predicate createLessEqualComparable( + Expression propertyPath, Y argument, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.lessThanOrEqualTo(propertyPath, argument); + } + + /** + * Apply a "in" constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param arguments + * List of arguments. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createIn(Expression propertyPath, List arguments, EntityManager manager) { + return propertyPath.in(arguments); + } + + /** + * Apply a "not in" (out) constraint to the property path. + * + * @param propertyPath + * Property path that we want to compare. + * @param arguments + * List of arguments. + * @param manager + * JPA EntityManager. + * @return Predicate a predicate representation. + */ + private static Predicate createNotIn(Expression propertyPath, List arguments, EntityManager manager) { + CriteriaBuilder builder = manager.getCriteriaBuilder(); + return builder.not(createIn(propertyPath, arguments, manager)); + } + + /** + * Verify if a property is an Association type. + * + * @param property + * Property to verify. + * @param classMetadata + * Metamodel of the class we want to check. + * @return true if the property is an associantion, false + * otherwise. + */ + private static boolean isAssociationType(String property, ManagedType classMetadata) { + return classMetadata.getAttribute(property).isAssociation(); + } + + /** + * Verify if a property is an Embedded type. + * + * @param property + * Property to verify. + * @param classMetadata + * Metamodel of the class we want to check. + * @return true if the property is an embedded attribute, + * false otherwise. + */ + private static boolean isEmbeddedType(String property, ManagedType classMetadata) { + return classMetadata.getAttribute(property).getPersistentAttributeType() == PersistentAttributeType.EMBEDDED; + } + + /** + * Verifies if a class metamodel has the specified property. + * + * @param property + * Property name. + * @param classMetadata + * Class metamodel that may hold that property. + * @return true if the class has that property, false + * otherwise. + */ + private static boolean hasPropertyName(String property, ManagedType classMetadata) { + Set> names = classMetadata.getAttributes(); + for (Attribute name : names) { + if (name.getName().equals(property)) + return true; + } + return false; + } + + /** + * Get the property Type out of the metamodel. + * + * @param property + * Property name for type extraction. + * @param classMetadata + * Reference class metamodel that holds property type. + * @return Class java type for the property, if the property is a + * pluralAttribute it will take the bindable java type of that + * collection. + */ + private static Class findPropertyType(String property, ManagedType classMetadata) { + Class propertyType = null; + if (classMetadata.getAttribute(property).isCollection()) { + propertyType = ((PluralAttribute) classMetadata.getAttribute(property)).getBindableJavaType(); + } else { + propertyType = classMetadata.getAttribute(property).getJavaType(); + } + return propertyType; + } + + /** + * Verifies if the argument is null. + * + * @param argument + * @return true if argument is null, false otherwise + */ + private static boolean isNullArgument(Object argument) { + return argument == null; + } + + /** + * Get date regarding the operation (less then or greater than) + * + * @param argument + * Date to be modified + * @param days + * Days to be added or removed form argument; + * @return Date modified date + */ + private static Date modifyDate(Object argument, int days) { + Date date = (Date) argument; + Calendar c = Calendar.getInstance(); + c.setTime(date); + c.add(Calendar.DATE, days); + date = c.getTime(); + return date; + } + + /** + * Builds an error message that reports that the argument is not suitable for + * use with the comparison operator. + * + * @param operator + * operator from the RSQL query + * @param argument + * actual argument produced from the ArgumentParser + * @return Error message for use in an Exception + */ + private static String buildNotComparableMessage(ComparisonOperator operator, Object argument) { + return String.format("Invalid type for comparison operator: %s type: %s must implement Comparable<%s>", + operator, argument.getClass().getName(), argument.getClass().getSimpleName()); + } } diff --git a/src/test/java/com/github/tennaito/rsql/jpa/AbstractVisitorTest.java b/src/test/java/com/github/tennaito/rsql/jpa/AbstractVisitorTest.java index 68916db..1ed5591 100644 --- a/src/test/java/com/github/tennaito/rsql/jpa/AbstractVisitorTest.java +++ b/src/test/java/com/github/tennaito/rsql/jpa/AbstractVisitorTest.java @@ -23,19 +23,22 @@ */ package com.github.tennaito.rsql.jpa; +import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.EntityManager; +import javax.persistence.metamodel.EntityType; -import com.github.tennaito.rsql.jpa.entity.Teacher; import org.junit.BeforeClass; import com.github.tennaito.rsql.jpa.entity.Course; import com.github.tennaito.rsql.jpa.entity.CourseDetails; import com.github.tennaito.rsql.jpa.entity.Department; import com.github.tennaito.rsql.jpa.entity.Person; +import com.github.tennaito.rsql.jpa.entity.PersonDependent; +import com.github.tennaito.rsql.jpa.entity.Teacher; import com.github.tennaito.rsql.jpa.entity.Title; /** @@ -43,65 +46,108 @@ */ public abstract class AbstractVisitorTest { - private static boolean loaded = false; + private static boolean loaded = false; protected Class entityClass; protected EntityManager entityManager; - @BeforeClass - public static void setUpBefore() throws Exception { - if (!loaded) { - - EntityManager entityManager = EntityManagerFactoryInitializer.getEntityManagerFactory().createEntityManager(); - entityManager.getTransaction().begin(); - - Title title1 = new Title(); - title1.setId(1L); - title1.setName("Phd"); - entityManager.persist(title1); - - Title title2 = new Title(); - title2.setId(2L); - title2.setName("Consultant"); - entityManager.persist(title2); - - Set titles = new HashSet<Title>(); - titles.add(title1); - titles.add(title2); - - Person head = new Person(); - head.setId(1L); - head.setName("Some"); - head.setSurname("One"); - head.setTitles(titles); - entityManager.persist(head); - - Department department = new Department(); - department.setId(1L); - department.setName("Testing"); - department.setCode("MI-MDW"); - department.setHead(head); - entityManager.persist(department); - - Teacher teacher = new Teacher(); - teacher.setId(23L); - teacher.setSpecialtyDescription("Maths"); - entityManager.persist(teacher); - - Course c = new Course(); - c.setId(1L); - c.setCode("MI-MDW"); - c.setActive(true); - c.setCredits(10); - c.setName("Testing Course"); - c.setDepartment(department); - c.setDetails(CourseDetails.of("test")); - c.getDetails().setTeacher(teacher); - c.setStartDate( new Date()); - entityManager.persist(c); - - entityManager.getTransaction().commit(); - loaded = true; - } - } + @BeforeClass + public static void setUpBefore() throws Exception { + if (!loaded) { + + EntityManager entityManager = EntityManagerFactoryInitializer.getEntityManagerFactory() + .createEntityManager(); + entityManager.getTransaction().begin(); + + Title title1 = new Title(); + title1.setId(1L); + title1.setName("Phd"); + entityManager.persist(title1); + + Title title2 = new Title(); + title2.setId(2L); + title2.setName("Consultant"); + entityManager.persist(title2); + + Set<Title> titles = new HashSet<Title>(); + titles.add(title1); + titles.add(title2); + + Person head = new Person(); + head.setId(1L); + head.setName("Some"); + head.setSurname("One"); + head.setTitles(titles); + entityManager.persist(head); + + Department department = new Department(); + department.setId(1L); + department.setName("Testing"); + department.setCode("MI-MDW"); + department.setHead(head); + entityManager.persist(department); + + Teacher teacher = new Teacher(); + teacher.setId(23L); + teacher.setSpecialtyDescription("Maths"); + entityManager.persist(teacher); + + + + Title titleCourse1 = new Title(); + titleCourse1.setId(100L); + titleCourse1.setName("course 1"); + + Title titleCourse2 = new Title(); + titleCourse2.setId(101L); + titleCourse2.setName("course 2"); + + Title titleCourse3 = new Title(); + titleCourse3.setId(102L); + titleCourse3.setName("course 3"); + + + Course c = new Course(); + c.setId(1L); + c.setCode("MI-MDW"); + c.setActive(true); + c.setCredits(10); + c.setName("Testing Course"); + c.setDepartment(department); + c.setDetails(CourseDetails.of("test")); + c.getDetails().setTeacher(teacher); + c.setStartDate(new Date()); + c.getTitles().addAll(Arrays.asList(titleCourse1,titleCourse2,titleCourse3)); + entityManager.persist(c); + + if (hasEntity(PersonDependent.class)) { + + PersonDependent dependent = new PersonDependent(); + dependent.setAge(2); + dependent.getId().setName("son1"); + dependent.getId().setPerson(head); + entityManager.persist(dependent); + + } + + entityManager.getTransaction().commit(); + loaded = true; + } + } + + public static boolean hasEntity(Class<?> clazz) { + + Set<EntityType<?>> entities = EntityManagerFactoryInitializer.getEntityManagerFactory().getMetamodel() + .getEntities(); + + for (EntityType<?> entityType : entities) { + + if (entityType.getJavaType().equals(clazz)) { + return true; + } + + } + + return false; + } } diff --git a/src/test/java/com/github/tennaito/rsql/jpa/JpaVisitorTest.java b/src/test/java/com/github/tennaito/rsql/jpa/JpaVisitorTest.java index c61a0c5..96b1b8d 100644 --- a/src/test/java/com/github/tennaito/rsql/jpa/JpaVisitorTest.java +++ b/src/test/java/com/github/tennaito/rsql/jpa/JpaVisitorTest.java @@ -23,12 +23,8 @@ */ package com.github.tennaito.rsql.jpa; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.fail; +import static junit.framework.Assert.*; +import static org.junit.Assert.assertThat; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -51,6 +47,7 @@ import com.github.tennaito.rsql.builder.BuilderTools; import com.github.tennaito.rsql.jpa.entity.Course; +import com.github.tennaito.rsql.jpa.entity.PersonDependent; import com.github.tennaito.rsql.misc.SimpleMapper; import com.github.tennaito.rsql.parser.ast.ComparisonOperatorProxy; @@ -68,392 +65,401 @@ */ public class JpaVisitorTest extends AbstractVisitorTest<Course> { - final static XorNode xorNode = new XorNode(new ArrayList<Node>()); - + final static XorNode xorNode = new XorNode(new ArrayList<Node>()); + @Before public void setUp() throws Exception { - entityManager = EntityManagerFactoryInitializer.getEntityManagerFactory().createEntityManager(); + entityManager = EntityManagerFactoryInitializer.getEntityManagerFactory().createEntityManager(); entityClass = Course.class; } @Test public void testUnknowProperty() throws Exception { - try { - Node rootNode = new RSQLParser().parse("invalid==1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("Unknown property: invalid from entity " + Course.class.getName(), e.getMessage()); - } + try { + Node rootNode = new RSQLParser().parse("invalid==1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Unknown property: invalid from entity " + Course.class.getName(), e.getMessage()); + } } - + @Test public void testSimpleSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id==1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("id==1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); } - + @Test public void testSimpleSelectionWhenPassingArgumentInTemplate() throws Exception { - Node rootNode = new RSQLParser().parse("id==1"); - // not a recommended usage - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(new Course()); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("id==1"); + // not a recommended usage + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(new Course()); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); } - @Test public void testNotEqualSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id!=1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("id!=1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(0, courses.size()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(0, courses.size()); } @Test public void testGreaterThanSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id=gt=1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(0, courses.size()); - } - - @Test - public void testGreaterThanDate() throws Exception { - Node rootNode = new RSQLParser().parse("startDate=gt='2001-01-01'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(1, courses.size()); - } - - @Test - public void testGreaterThanString() throws Exception { - Node rootNode = new RSQLParser().parse("code=gt='ABC'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(1, courses.size()); - } - - @Test - public void testGreaterThanNotComparable() throws Exception { - try { - Node rootNode = new RSQLParser().parse("details.teacher=gt='ABC'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - rootNode.accept(visitor, entityManager); - fail("should have failed since type isn't Comparable"); - } catch (IllegalArgumentException e) { - assertEquals("Invalid type for comparison operator: =gt= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", e.getMessage()); - } - } - - @Test - public void testGreaterThanEqualSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id=ge=1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testGreaterThanEqualSelectionForDate() throws Exception { - Node rootNode = new RSQLParser().parse("startDate=ge='2016-01-01'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testGreaterThanEqualSelectionForString() throws Exception { - Node rootNode = new RSQLParser().parse("code=ge='MI-MDW'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testGreaterThanEqualNotComparable() throws Exception { - try { - Node rootNode = new RSQLParser().parse("details.teacher=ge='ABC'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - rootNode.accept(visitor, entityManager); - fail("should have failed since type isn't Comparable"); - } catch (IllegalArgumentException e) { - assertEquals("Invalid type for comparison operator: =ge= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", e.getMessage()); - } - } - - @Test + Node rootNode = new RSQLParser().parse("id=gt=1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(0, courses.size()); + } + + @Test + public void testGreaterThanDate() throws Exception { + Node rootNode = new RSQLParser().parse("startDate=gt='2001-01-01'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(1, courses.size()); + } + + @Test + public void testGreaterThanString() throws Exception { + Node rootNode = new RSQLParser().parse("code=gt='ABC'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(1, courses.size()); + } + + @Test + public void testGreaterThanNotComparable() throws Exception { + try { + Node rootNode = new RSQLParser().parse("details.teacher=gt='ABC'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + rootNode.accept(visitor, entityManager); + fail("should have failed since type isn't Comparable"); + } catch (IllegalArgumentException e) { + assertEquals( + "Invalid type for comparison operator: =gt= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", + e.getMessage()); + } + } + + @Test + public void testGreaterThanEqualSelection() throws Exception { + Node rootNode = new RSQLParser().parse("id=ge=1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testGreaterThanEqualSelectionForDate() throws Exception { + Node rootNode = new RSQLParser().parse("startDate=ge='2016-01-01'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testGreaterThanEqualSelectionForString() throws Exception { + Node rootNode = new RSQLParser().parse("code=ge='MI-MDW'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testGreaterThanEqualNotComparable() throws Exception { + try { + Node rootNode = new RSQLParser().parse("details.teacher=ge='ABC'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + rootNode.accept(visitor, entityManager); + fail("should have failed since type isn't Comparable"); + } catch (IllegalArgumentException e) { + assertEquals( + "Invalid type for comparison operator: =ge= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", + e.getMessage()); + } + } + + @Test public void testLessThanSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id=lt=1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("id=lt=1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(0, courses.size()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(0, courses.size()); } @Test public void testLessThanEqualSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id=le=1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testLessThanDate() throws Exception { - Node rootNode = new RSQLParser().parse("startDate=lt='2222-02-02'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(1, courses.size()); - } - - @Test - public void testLessThanString() throws Exception { - Node rootNode = new RSQLParser().parse("code=lt='MI-MDZ'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(1, courses.size()); - } - - @Test - public void testLessThanNotComparable() throws Exception { - try { - Node rootNode = new RSQLParser().parse("details.teacher=lt='ABC'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - rootNode.accept(visitor, entityManager); - fail("should have failed since type isn't Comparable"); - } catch (IllegalArgumentException e) { - assertEquals("Invalid type for comparison operator: =lt= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", e.getMessage()); - } - } - - @Test - public void testLessThanEqualSelectionForDate() throws Exception { - Node rootNode = new RSQLParser().parse("startDate=le='2100-01-01'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testLessThanEqualSelectionForString() throws Exception { - Node rootNode = new RSQLParser().parse("code=le='MI-MDW'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testLessThanEqualNotComparable() throws Exception { - try { - Node rootNode = new RSQLParser().parse("details.teacher=le='ABC'"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - rootNode.accept(visitor, entityManager); - fail("should have failed since type isn't Comparable"); - } catch (IllegalArgumentException e) { - assertEquals("Invalid type for comparison operator: =le= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", e.getMessage()); - } - } - - - @Test + Node rootNode = new RSQLParser().parse("id=le=1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testLessThanDate() throws Exception { + Node rootNode = new RSQLParser().parse("startDate=lt='2222-02-02'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(1, courses.size()); + } + + @Test + public void testLessThanString() throws Exception { + Node rootNode = new RSQLParser().parse("code=lt='MI-MDZ'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(1, courses.size()); + } + + @Test + public void testLessThanNotComparable() throws Exception { + try { + Node rootNode = new RSQLParser().parse("details.teacher=lt='ABC'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + rootNode.accept(visitor, entityManager); + fail("should have failed since type isn't Comparable"); + } catch (IllegalArgumentException e) { + assertEquals( + "Invalid type for comparison operator: =lt= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", + e.getMessage()); + } + } + + @Test + public void testLessThanEqualSelectionForDate() throws Exception { + Node rootNode = new RSQLParser().parse("startDate=le='2100-01-01'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testLessThanEqualSelectionForString() throws Exception { + Node rootNode = new RSQLParser().parse("code=le='MI-MDW'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testLessThanEqualNotComparable() throws Exception { + try { + Node rootNode = new RSQLParser().parse("details.teacher=le='ABC'"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + rootNode.accept(visitor, entityManager); + fail("should have failed since type isn't Comparable"); + } catch (IllegalArgumentException e) { + assertEquals( + "Invalid type for comparison operator: =le= type: com.github.tennaito.rsql.jpa.entity.Teacher must implement Comparable<Teacher>", + e.getMessage()); + } + } + + @Test public void testInSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id=in=(1,2,3,4)"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("id=in=(1,2,3,4)"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); } @Test public void testOutSelection() throws Exception { - Node rootNode = new RSQLParser().parse("id=out=(1,2,3,4)"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("id=out=(1,2,3,4)"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(0, courses.size()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(0, courses.size()); } @Test public void testLikeSelection() throws Exception { - Node rootNode = new RSQLParser().parse("name==*Course"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("name==*Course"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); } @Test public void testNotLikeSelection() throws Exception { - Node rootNode = new RSQLParser().parse("name!=*Course"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("name!=*Course"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(0, courses.size()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(0, courses.size()); } - @Test public void testIsNullSelection() throws Exception { - Node rootNode = new RSQLParser().parse("name==null"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("name==null"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals(0, courses.size()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals(0, courses.size()); } @Test public void testNotIsNullSelection() throws Exception { - Node rootNode = new RSQLParser().parse("name!=null"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("name!=null"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); } @Test public void testSetEntity() { Node rootNode = new RSQLParser().parse("id==1"); RSQLVisitor<CriteriaQuery<?>, EntityManager> visitor = new JpaCriteriaQueryVisitor(); - ((JpaCriteriaQueryVisitor)visitor).setEntityClass(Course.class); + ((JpaCriteriaQueryVisitor) visitor).setEntityClass(Course.class); CriteriaQuery<?> query = rootNode.accept(visitor, entityManager); - List<Course> courses = (List<Course>)entityManager.createQuery(query).getResultList(); + List<Course> courses = (List<Course>) entityManager.createQuery(query).getResultList(); assertEquals(1, courses.size()); } @Test - public void testUndefinedComparisonOperator() { - try { - ComparisonOperator newOp = new ComparisonOperator("=def="); - Set<ComparisonOperator> set = new HashSet<ComparisonOperator>(); - set.add(newOp); - Node rootNode = new RSQLParser(set).parse("id=def=null"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - fail(); - } catch(Exception e) { - assertEquals("Unknown operator: =def=", e.getMessage()); - } - } + public void testUndefinedComparisonOperator() { + try { + ComparisonOperator newOp = new ComparisonOperator("=def="); + Set<ComparisonOperator> set = new HashSet<ComparisonOperator>(); + set.add(newOp); + Node rootNode = new RSQLParser(set).parse("id=def=null"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + List<Course> courses = entityManager.createQuery(query).getResultList(); + fail(); + } catch (Exception e) { + assertEquals("Unknown operator: =def=", e.getMessage()); + } + } - @Test + @Test public void testDefinedComparisonOperator() { - // define the new operator - ComparisonOperator newOp = new ComparisonOperator("=def="); - Set<ComparisonOperator> set = new HashSet<ComparisonOperator>(); - set.add(newOp); - // execute parser - Node rootNode = new RSQLParser(set).parse("id=def=1"); - - JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); - createDefOperator(visitor); - - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - private void createDefOperator(JpaCriteriaQueryVisitor<Course> visitor) { - // define new operator resolver - PredicateBuilderStrategy predicateStrategy = new PredicateBuilderStrategy() { - public <T> Predicate createPredicate(Node node, From root, Class<T> entity, - EntityManager manager, BuilderTools tools) - throws IllegalArgumentException { - ComparisonNode comp = ((ComparisonNode)node); - ComparisonNode def = new ComparisonNode(ComparisonOperatorProxy.EQUAL.getOperator(), comp.getSelector(), comp.getArguments()); - return PredicateBuilder.createPredicate(def, root, entity, manager, tools); - } - }; - visitor.getBuilderTools().setPredicateBuilder(predicateStrategy); - } + // define the new operator + ComparisonOperator newOp = new ComparisonOperator("=def="); + Set<ComparisonOperator> set = new HashSet<ComparisonOperator>(); + set.add(newOp); + // execute parser + Node rootNode = new RSQLParser(set).parse("id=def=1"); + + JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); + createDefOperator(visitor); + + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + private void createDefOperator(JpaCriteriaQueryVisitor<Course> visitor) { + // define new operator resolver + PredicateBuilderStrategy predicateStrategy = new PredicateBuilderStrategy() { + public <T> Predicate createPredicate(Node node, From root, Class<T> entity, + EntityManager manager, BuilderTools tools) + throws IllegalArgumentException { + ComparisonNode comp = ((ComparisonNode) node); + ComparisonNode def = new ComparisonNode(ComparisonOperatorProxy.EQUAL.getOperator(), comp.getSelector(), + comp.getArguments()); + return PredicateBuilder.createPredicate(def, root, entity, manager, tools); + } + }; + visitor.getBuilderTools().setPredicateBuilder(predicateStrategy); + } @Test public void testAssociationSelection() throws Exception { - Node rootNode = new RSQLParser().parse("department.id==1"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testAssociationAliasSelection() throws Exception { - Node rootNode = new RSQLParser().parse("dept.id==1"); - JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); - // add to SimpleMapper - assertNotNull(((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).getMapping()); - ((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, new HashMap<String, String>()); - ((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, "dept", "department"); - - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - - ((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).setMapping(null); - assertNull(((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).getMapping()); - } - - @Test - public void testAssociationAliasSelectionWithAssociationAlias() throws Exception { - Node rootNode = new RSQLParser().parse("dept_id==1"); - JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); - // add to SimpleMapper - assertNotNull(((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).getMapping()); - ((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, new HashMap<String, String>()); - ((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, "dept_id", "department.id"); - - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - - ((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).setMapping(null); - assertNull(((SimpleMapper)visitor.getBuilderTools().getPropertiesMapper()).getMapping()); - } - - @Test + Node rootNode = new RSQLParser().parse("department.id==1"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testAssociationAliasSelection() throws Exception { + Node rootNode = new RSQLParser().parse("dept.id==1"); + JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); + // add to SimpleMapper + assertNotNull(((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).getMapping()); + ((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, + new HashMap<String, String>()); + ((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, "dept", "department"); + + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + + ((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).setMapping(null); + assertNull(((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).getMapping()); + } + + @Test + public void testAssociationAliasSelectionWithAssociationAlias() throws Exception { + Node rootNode = new RSQLParser().parse("dept_id==1"); + JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); + // add to SimpleMapper + assertNotNull(((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).getMapping()); + ((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, + new HashMap<String, String>()); + ((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).addMapping(Course.class, "dept_id", + "department.id"); + + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + + ((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).setMapping(null); + assertNull(((SimpleMapper) visitor.getBuilderTools().getPropertiesMapper()).getMapping()); + } + + @Test public void testAndSelection() throws Exception { Node rootNode = new RSQLParser().parse("department.id==1;id==2"); RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); @@ -463,37 +469,37 @@ public void testAndSelection() throws Exception { assertEquals(0, courses.size()); } - @Test - public void testBasicSelectionCount() throws Exception { - Node rootNode = new RSQLParser().parse("department.id==1"); - RSQLVisitor<CriteriaQuery<Long>, EntityManager> visitor = new JpaCriteriaCountQueryVisitor<Course>(); - CriteriaQuery<Long> query = rootNode.accept(visitor, entityManager); + @Test + public void testBasicSelectionCount() throws Exception { + Node rootNode = new RSQLParser().parse("department.id==1"); + RSQLVisitor<CriteriaQuery<Long>, EntityManager> visitor = new JpaCriteriaCountQueryVisitor<Course>(); + CriteriaQuery<Long> query = rootNode.accept(visitor, entityManager); - Long courseCount = entityManager.createQuery(query).getSingleResult(); - assertEquals((Long)1l, courseCount); - Root<Course> root = ((JpaCriteriaCountQueryVisitor<Course>)visitor).getRoot(); - assertNotNull(root); - ((JpaCriteriaCountQueryVisitor<Course>)visitor).setRoot(root); - } + Long courseCount = entityManager.createQuery(query).getSingleResult(); + assertEquals((Long) 1l, courseCount); + Root<Course> root = ((JpaCriteriaCountQueryVisitor<Course>) visitor).getRoot(); + assertNotNull(root); + ((JpaCriteriaCountQueryVisitor<Course>) visitor).setRoot(root); + } - @Test + @Test public void testAndSelectionCount() throws Exception { Node rootNode = new RSQLParser().parse("department.id==1;id==2"); RSQLVisitor<CriteriaQuery<Long>, EntityManager> visitor = new JpaCriteriaCountQueryVisitor<Course>(); CriteriaQuery<Long> query = rootNode.accept(visitor, entityManager); Long courseCount = entityManager.createQuery(query).getSingleResult(); - assertEquals((Long)0l, courseCount); + assertEquals((Long) 0l, courseCount); } @Test public void testOrSelection() throws Exception { - Node rootNode = new RSQLParser().parse("department.id==1,id==2"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("department.id==1,id==2"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); } @Test @@ -503,172 +509,209 @@ public void testOrSelectionCount() throws Exception { CriteriaQuery<Long> query = rootNode.accept(visitor, entityManager); Long courseCount = entityManager.createQuery(query).getSingleResult(); - assertEquals((Long)1l, courseCount); + assertEquals((Long) 1l, courseCount); } @Test public void testVariousNodesSelection() throws Exception { - Node rootNode = new RSQLParser().parse("((department.id==1;id==2),id<3);department.id=out=(3,4,5)"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("((department.id==1;id==2),id<3);department.id=out=(3,4,5)"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); } - + @Test public void testNavigateThroughCollectionSelection() throws Exception { - Node rootNode = new RSQLParser().parse("department.head.titles.name==Phd"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + Node rootNode = new RSQLParser().parse("department.head.titles.name==Phd"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + + + assertEquals(courses.size(), 1); } - + @Test public void testUnsupportedNode() throws Exception { - try{ - PredicateBuilder.createPredicate(new OtherNode(), null, null, null, null); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("Unknown expression type: class com.github.tennaito.rsql.jpa.JpaVisitorTest$OtherNode", e.getMessage()); - } + try { + PredicateBuilder.createPredicate(new OtherNode(), null, null, null, null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Unknown expression type: class com.github.tennaito.rsql.jpa.JpaVisitorTest$OtherNode", + e.getMessage()); + } } - + @Test public void testSetBuilderTools() throws Exception { - JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); - visitor.setBuilderTools(null); - assertNotNull(visitor.getBuilderTools()); - - visitor.getBuilderTools().setArgumentParser(null); - assertNotNull(visitor.getBuilderTools().getArgumentParser()); - - visitor.getBuilderTools().setPropertiesMapper(null); - assertNotNull(visitor.getBuilderTools().getPropertiesMapper()); - - visitor.getBuilderTools().setPredicateBuilder(null); - assertNull(visitor.getBuilderTools().getPredicateBuilder()); - } - + JpaCriteriaQueryVisitor<Course> visitor = new JpaCriteriaQueryVisitor<Course>(); + visitor.setBuilderTools(null); + assertNotNull(visitor.getBuilderTools()); + + visitor.getBuilderTools().setArgumentParser(null); + assertNotNull(visitor.getBuilderTools().getArgumentParser()); + + visitor.getBuilderTools().setPropertiesMapper(null); + assertNotNull(visitor.getBuilderTools().getPropertiesMapper()); + + visitor.getBuilderTools().setPredicateBuilder(null); + assertNull(visitor.getBuilderTools().getPredicateBuilder()); + } + @Test public void testUnsupportedLogicalNode() throws Exception { - try{ - PredicateBuilder.createPredicate(JpaVisitorTest.xorNode, null, Course.class, entityManager, null); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("Unknown operator: ^", e.getMessage()); - } + try { + PredicateBuilder.createPredicate(JpaVisitorTest.xorNode, null, Course.class, entityManager, null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Unknown operator: ^", e.getMessage()); + } } - + @Test public void testPrivateConstructor() throws Exception { - Constructor<PredicateBuilder> priv = PredicateBuilder.class.getDeclaredConstructor(); - // It is really private? - assertFalse(priv.isAccessible()); - priv.setAccessible(true); - Object predicateBuilder = priv.newInstance(); - // When used it returns a instance? - assertNotNull(predicateBuilder); - } - + Constructor<PredicateBuilder> priv = PredicateBuilder.class.getDeclaredConstructor(); + // It is really private? + assertFalse(priv.isAccessible()); + priv.setAccessible(true); + Object predicateBuilder = priv.newInstance(); + // When used it returns a instance? + assertNotNull(predicateBuilder); + } + ////////////////////////// Mocks ////////////////////////// - + protected static class OtherNode extends AbstractNode { - public <R, A> R accept(RSQLVisitor<R, A> visitor, A param) { - throw new UnsupportedOperationException(); - } + public <R, A> R accept(RSQLVisitor<R, A> visitor, A param) { + throw new UnsupportedOperationException(); + } } - + protected static class XorNode extends LogicalNode { - final static LogicalOperator XOR = createLogicalOperatorXor(); - - public XorNode(List<? extends Node> children) { - super(XOR, children); - } - - public static void setStaticFinalField(Field field, Object value) throws NoSuchFieldException, IllegalAccessException { - // we mark the field to be public - field.setAccessible(true); - // next we change the modifier in the Field instance to - // not be final anymore, thus tricking reflection into - // letting us modify the static final field - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - int modifiers = modifiersField.getInt(field); - // blank out the final bit in the modifiers int - modifiers &= ~Modifier.FINAL; - modifiersField.setInt(field, modifiers); - sun.reflect.FieldAccessor fa = sun.reflect.ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false); - fa.set(null, value); - } - - private static LogicalOperator createLogicalOperatorXor() { - LogicalOperator xor = null; - try { - Constructor<LogicalOperator> cstr = LogicalOperator.class.getDeclaredConstructor(String.class, int.class, String.class); - sun.reflect.ReflectionFactory factory = sun.reflect.ReflectionFactory.getReflectionFactory(); - xor = (LogicalOperator) factory.newConstructorAccessor(cstr).newInstance(new Object[]{"XOR", 2, "^"}); - - Field ordinalField = Enum.class.getDeclaredField("ordinal"); - ordinalField.setAccessible(true); - - LogicalOperator[] values = xor.values(); - Field valuesField = LogicalOperator.class.getDeclaredField("ENUM$VALUES"); - valuesField.setAccessible(true); - LogicalOperator[] newValues = Arrays.copyOf(values, values.length + 1); - newValues[newValues.length - 1] = xor; - setStaticFinalField(valuesField, newValues); - int ordinal = newValues.length - 1; - ordinalField.set(xor, ordinal); - } catch (ReflectiveOperationException e) { - // do nothing - e.printStackTrace(); - } - return xor; - } - - @Override - public LogicalNode withChildren(List<? extends Node> children) { - return new XorNode(children); - } - - public <R, A> R accept(RSQLVisitor<R, A> visitor, A param) { - throw new UnsupportedOperationException(); - } - } - + final static LogicalOperator XOR = createLogicalOperatorXor(); + + public XorNode(List<? extends Node> children) { + super(XOR, children); + } + + public static void setStaticFinalField(Field field, Object value) + throws NoSuchFieldException, IllegalAccessException { + // we mark the field to be public + field.setAccessible(true); + // next we change the modifier in the Field instance to + // not be final anymore, thus tricking reflection into + // letting us modify the static final field + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + int modifiers = modifiersField.getInt(field); + // blank out the final bit in the modifiers int + modifiers &= ~Modifier.FINAL; + modifiersField.setInt(field, modifiers); + sun.reflect.FieldAccessor fa = sun.reflect.ReflectionFactory.getReflectionFactory().newFieldAccessor(field, + false); + fa.set(null, value); + } + + private static LogicalOperator createLogicalOperatorXor() { + LogicalOperator xor = null; + try { + Constructor<LogicalOperator> cstr = LogicalOperator.class.getDeclaredConstructor(String.class, + int.class, String.class); + sun.reflect.ReflectionFactory factory = sun.reflect.ReflectionFactory.getReflectionFactory(); + xor = (LogicalOperator) factory.newConstructorAccessor(cstr).newInstance(new Object[] {"XOR", 2, "^"}); + + Field ordinalField = Enum.class.getDeclaredField("ordinal"); + ordinalField.setAccessible(true); + + LogicalOperator[] values = xor.values(); + Field valuesField = LogicalOperator.class.getDeclaredField("ENUM$VALUES"); + valuesField.setAccessible(true); + LogicalOperator[] newValues = Arrays.copyOf(values, values.length + 1); + newValues[newValues.length - 1] = xor; + setStaticFinalField(valuesField, newValues); + int ordinal = newValues.length - 1; + ordinalField.set(xor, ordinal); + } catch (ReflectiveOperationException e) { + // do nothing + e.printStackTrace(); + } + return xor; + } + + @Override + public LogicalNode withChildren(List<? extends Node> children) { + return new XorNode(children); + } + + public <R, A> R accept(RSQLVisitor<R, A> visitor, A param) { + throw new UnsupportedOperationException(); + } + } + @Test public void testUndefinedRootForPredicate() throws Exception { - try { - Node rootNode = new RSQLParser().parse("id==1"); - RSQLVisitor<Predicate, EntityManager> visitor = new JpaPredicateVisitor<Course>(); - Predicate query = rootNode.accept(visitor, entityManager); - } catch (IllegalArgumentException e) { - assertEquals("From root node was undefined.", e.getMessage()); - } - } - - @Test - public void testSelectionUsingEmbeddedField() throws Exception { - Node rootNode = new RSQLParser().parse("details.description==test"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } - - @Test - public void testSelectionUsingEmbeddedAssociationField() throws Exception { - Node rootNode = new RSQLParser().parse("details.teacher.specialtyDescription==Maths"); - RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); - CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); - - List<Course> courses = entityManager.createQuery(query).getResultList(); - assertEquals("Testing Course", courses.get(0).getName()); - } + try { + Node rootNode = new RSQLParser().parse("id==1"); + RSQLVisitor<Predicate, EntityManager> visitor = new JpaPredicateVisitor<Course>(); + Predicate query = rootNode.accept(visitor, entityManager); + } catch (IllegalArgumentException e) { + assertEquals("From root node was undefined.", e.getMessage()); + } + } + + @Test + public void testSelectionUsingEmbeddedField() throws Exception { + Node rootNode = new RSQLParser().parse("details.description==test"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testSelectionUsingEmbeddedAssociationField() throws Exception { + Node rootNode = new RSQLParser().parse("details.teacher.specialtyDescription==Maths"); + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + } + + @Test + public void testSelectionUsingEmbeddedIdField() throws Exception { + + if (hasEntity(PersonDependent.class)) { + + Node rootNode = new RSQLParser().parse("id.person.name==Some"); + RSQLVisitor<CriteriaQuery<PersonDependent>, EntityManager> visitor = new JpaCriteriaQueryVisitor<PersonDependent>(); + CriteriaQuery<PersonDependent> query = rootNode.accept(visitor, entityManager); + + List<PersonDependent> listDependent = entityManager.createQuery(query).getResultList(); + assertEquals("son1", listDependent.get(0).getId().getName()); + + } + + } + + @Test + public void testFilterOneToMany() throws Exception { + Node rootNode = new RSQLParser().parse("titles.id>=100 and titles.id<=101"); + + RSQLVisitor<CriteriaQuery<Course>, EntityManager> visitor = new JpaCriteriaQueryVisitor<Course>(new Course()); + CriteriaQuery<Course> query = rootNode.accept(visitor, entityManager); + + List<Course> courses = entityManager.createQuery(query).getResultList(); + assertEquals("Testing Course", courses.get(0).getName()); + + assertEquals(2, courses.size()); + } + } diff --git a/src/test/java/com/github/tennaito/rsql/jpa/entity/Course.java b/src/test/java/com/github/tennaito/rsql/jpa/entity/Course.java index 50703be..a443d19 100644 --- a/src/test/java/com/github/tennaito/rsql/jpa/entity/Course.java +++ b/src/test/java/com/github/tennaito/rsql/jpa/entity/Course.java @@ -24,13 +24,20 @@ */ package com.github.tennaito.rsql.jpa.entity; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; +import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +import java.util.ArrayList; import java.util.Date; +import java.util.List; +import java.util.Set; /** * @@ -64,7 +71,10 @@ public class Course extends AbstractTestEntity { @Embedded private CourseDetails details; - + + @OneToMany(cascade=CascadeType.ALL) + private final List<Title> titles = new ArrayList<Title>(); + public boolean isActive() { return active; } @@ -120,4 +130,8 @@ public Date getEndDate() { public void setEndDate(Date endDate) { this.endDate = endDate; } + + public List<Title> getTitles() { + return titles; + } } diff --git a/src/test/java/com/github/tennaito/rsql/jpa/entity/PersonDependent.java b/src/test/java/com/github/tennaito/rsql/jpa/entity/PersonDependent.java new file mode 100644 index 0000000..14485c6 --- /dev/null +++ b/src/test/java/com/github/tennaito/rsql/jpa/entity/PersonDependent.java @@ -0,0 +1,30 @@ +package com.github.tennaito.rsql.jpa.entity; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; + +@Entity +public class PersonDependent { + + @EmbeddedId + private PersonDependentPK id = new PersonDependentPK(); + + private Integer age; + + public PersonDependentPK getId() { + return id; + } + + public void setId(PersonDependentPK id) { + this.id = id; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + +} diff --git a/src/test/java/com/github/tennaito/rsql/jpa/entity/PersonDependentPK.java b/src/test/java/com/github/tennaito/rsql/jpa/entity/PersonDependentPK.java new file mode 100644 index 0000000..7b2dd58 --- /dev/null +++ b/src/test/java/com/github/tennaito/rsql/jpa/entity/PersonDependentPK.java @@ -0,0 +1,37 @@ +package com.github.tennaito.rsql.jpa.entity; + +import java.io.Serializable; + +import javax.persistence.Embeddable; +import javax.persistence.ManyToOne; + +@Embeddable +public class PersonDependentPK implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @ManyToOne + private Person person; + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } + +} diff --git a/src/test/resources/META-INF/persistence.xml b/src/test/resources/META-INF/persistence.xml index 215c469..a950b46 100644 --- a/src/test/resources/META-INF/persistence.xml +++ b/src/test/resources/META-INF/persistence.xml @@ -4,6 +4,10 @@ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> + + + <!-- + <persistence-unit name="persistenceUnit"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>com.github.tennaito.rsql.jpa.entity.Course</class> @@ -25,13 +29,20 @@ </properties> </persistence-unit> - <!-- +--> + + + + + <!-- --> + <persistence-unit name="persistenceUnit"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>com.github.tennaito.rsql.jpa.entity.Course</class> <class>com.github.tennaito.rsql.jpa.entity.Department</class> <class>com.github.tennaito.rsql.jpa.entity.Person</class> <class>com.github.tennaito.rsql.jpa.entity.Title</class> + <class>com.github.tennaito.rsql.jpa.entity.PersonDependent</class> <properties> <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:ProductDAOTest" /> @@ -41,6 +52,10 @@ <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> </properties> - </persistence-unit> - --> + </persistence-unit> + + + + + </persistence>