package org.aksw.jena_sparql_api.mapper.jpa.criteria.expr; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import javax.persistence.criteria.Path; import org.aksw.jena_sparql_api.concepts.Relation; import org.aksw.jena_sparql_api.utils.Vars; import org.apache.jena.datatypes.RDFDatatype; import org.apache.jena.datatypes.TypeMapper; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; import org.apache.jena.sparql.expr.E_Equals; import org.apache.jena.sparql.expr.E_LogicalAnd; import org.apache.jena.sparql.expr.E_LogicalNot; import org.apache.jena.sparql.expr.Expr; import org.apache.jena.sparql.expr.ExprAggregator; import org.apache.jena.sparql.expr.ExprVar; import org.apache.jena.sparql.expr.NodeValue; import org.apache.jena.sparql.expr.aggregate.AggMax; import org.apache.jena.sparql.syntax.Element; import org.apache.jena.sparql.syntax.ElementFilter; /** * Compiles JPA criteria expressions to SPARQL expressions. * The principle is, that JPA path expressions are compiled to SPARQL graph patterns (Jena's Element), * of which have a 'target' variable. * The target variable can participate in further expressions. * * * * @author raven * */ public class ExpressionCompiler implements ExpressionVisitor<Expr> { protected TypeMapper typeMapper; protected Function<? super Path<?>, Relation> pathHandler; // // The elements assembled from the expressions protected List<Element> elements = new ArrayList<>(); public List<Element> getElements() { return elements; } public ExpressionCompiler(Function<? super Path<?>, Relation> pathHandler) { super(); this.pathHandler = pathHandler; this.typeMapper = TypeMapper.getInstance(); } public Expr visit(Path<?> e) { Relation relation = pathHandler.apply(e); if(relation == null) { throw new RuntimeException("Could not resolve path: " + e); } Element element = relation.getElement(); if(element != null) { elements.add(element); } Expr result = new ExprVar(relation.getTargetVar()); return result; }; @Override public Expr visit(EqualsExpression e) { Expr a = e.getLeftHandOperand().accept(this); Expr b = e.getRightHandOperand().accept(this); Expr result = new E_Equals(a, b); elements.add(new ElementFilter(result)); return result; } @Override public Expr visit(LogicalNotExpression e) { Expr a = e.accept(this); Expr result = new E_LogicalNot(a); return result; } @Override public Expr visit(GreatestExpression<?> e) { // Prepare a sub-query Expr expr = e.getOperand().accept(this); AggMax agg = new AggMax(expr); Expr result = new ExprAggregator(Vars.x, agg); return result; } @Override public Expr visit(ValueExpression<?> e) { Object value = e.getValue(); RDFDatatype rdfDatatype = typeMapper.getTypeByValue(value); Node node = NodeFactory.createLiteralByValue(value, rdfDatatype); NodeValue result = NodeValue.makeNode(node); return result; } @Override public Expr visit(LogicalAndExpression e) { Expr a = e.getLeftHandOperand().accept(this); Expr b = e.getRightHandOperand().accept(this); // TODO This way of implementation is certainly wrong - do it right return new E_LogicalAnd(a, b); } }