Last active
September 21, 2020 08:28
-
-
Save jirutka/42a0f9bfea280b3c5dca to your computer and use it in GitHub Desktop.
Very simple, quick & dirty implementation of RSQL to JPA2 converter. See https://github.com/jirutka/rsql-parser.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cz.jirutka.rsql.parser.ast.*; | |
import org.springframework.core.convert.ConversionService; | |
import org.springframework.core.convert.support.DefaultConversionService; | |
import javax.persistence.criteria.CriteriaBuilder; | |
import javax.persistence.criteria.Path; | |
import javax.persistence.criteria.Predicate; | |
import javax.persistence.criteria.Root; | |
import javax.persistence.metamodel.Attribute; | |
import java.util.List; | |
import static cz.jirutka.rsql.parser.ast.RSQLOperators.*; | |
// WARNING: This is very naive, quick & dirty implementation! | |
public class JpaRsqlConverter implements RSQLVisitor<Predicate, Root> { | |
private final CriteriaBuilder builder; | |
private final ConversionService conversionService = new DefaultConversionService(); | |
public JpaRsqlConverter(CriteriaBuilder builder) { | |
this.builder = builder; | |
} | |
public Predicate visit(AndNode node, Root root) { | |
return builder.and(processNodes(node.getChildren(), root)); | |
} | |
public Predicate visit(OrNode node, Root root) { | |
return builder.or(processNodes(node.getChildren(), root)); | |
} | |
public Predicate visit(ComparisonNode node, Root root) { | |
ComparisonOperator op = node.getOperator(); | |
Path attrPath = root.get(node.getSelector()); | |
// RSQL guarantees that node has at least one argument | |
Object argument = node.getArguments().get(0); | |
if (op.equals(EQUAL)) { | |
return builder.equal(attrPath, argument); | |
} | |
if (op.equals(NOT_EQUAL)) { | |
return builder.notEqual(attrPath, argument); | |
} | |
Attribute attribute = root.getModel().getAttribute(node.getSelector()); | |
Class type = attribute.getJavaType(); | |
if (! Comparable.class.isAssignableFrom(type)) { | |
throw new IllegalArgumentException(String.format( | |
"Operator %s can be used only for Comparables", op)); | |
} | |
Comparable comparable = (Comparable) conversionService.convert(argument, type); | |
if (op.equals(GREATER_THAN)) { | |
return builder.greaterThan(attrPath, comparable); | |
} | |
if (op.equals(GREATER_THAN_OR_EQUAL)) { | |
return builder.greaterThanOrEqualTo(attrPath, comparable); | |
} | |
if (op.equals(LESS_THAN)) { | |
return builder.lessThan(attrPath, comparable); | |
} | |
if (op.equals(LESS_THAN_OR_EQUAL)) { | |
return builder.lessThanOrEqualTo(attrPath, comparable); | |
} | |
throw new IllegalArgumentException("Unknown operator: " + op); | |
} | |
private Predicate[] processNodes(List<Node> nodes, Root root) { | |
Predicate[] predicates = new Predicate[nodes.size()]; | |
for (int i = 0; i < nodes.size(); i++) { | |
predicates[i] = nodes.get(i).accept(this, root); | |
} | |
return predicates; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.springframework.data.domain.Pageable; | |
import org.springframework.web.bind.annotation.RequestParam; | |
import java.lang.Iterable; | |
/** | |
* Simple controller example. | |
*/ | |
@RestController | |
@RequestMapping("/projects") | |
public class ProjectsController { | |
@RequestMapping | |
public Iterable<Project> findProjects(@RequestParam String query, Pageable pageable) { | |
return repository.findAll(RsqlSpecification.<Project>rsql(query), pageable); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cz.jirutka.rsql.parser.ast.Node; | |
import cz.jirutka.rsql.parser.RSQLParser; | |
import org.springframework.data.jpa.domain.Specification; | |
import javax.persistence.criteria.CriteriaBuilder; | |
import javax.persistence.criteria.CriteriaQuery; | |
import javax.persistence.criteria.Predicate; | |
import javax.persistence.criteria.Root; | |
public abstract class RsqlSpecification { | |
public static <T> Specification<T> rsql(final String rsqlQuery) { | |
return new Specification<T>() { | |
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) { | |
Node rsql = new RSQLParser().parse(rsqlQuery); | |
return rsql.accept(new JpaRsqlConverter(cb), root); | |
} | |
}; | |
} | |
} |
How do I get generic-type here?
Attribute attribute = root.getModel().getAttribute(node.getSelector());
Class type = attribute.getJavaType();
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
to support like operations