Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement/176 soql member of #187

Merged
merged 9 commits into from
Jul 22, 2023

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import cz.cvut.kbss.jopa.model.query.criteria.Expression;
import cz.cvut.kbss.jopa.model.query.criteria.Predicate;

import java.util.Collection;

public interface PredicateFactory {

/**
Expand Down Expand Up @@ -112,7 +114,8 @@ public interface PredicateFactory {
* @param y expression
* @return greaterThanOrEqual predicate
*/
<Y extends Comparable<? super Y>> Predicate greaterThanOrEqual(Expression<? extends Y> x, Expression<? extends Y> y);
<Y extends Comparable<? super Y>> Predicate greaterThanOrEqual(Expression<? extends Y> x,
Expression<? extends Y> y);

/**
* Create a predicate for testing whether the first argument is greater than or equal to the second.
Expand Down Expand Up @@ -186,6 +189,26 @@ public interface PredicateFactory {
*/
Predicate notLike(Expression<String> x, String pattern);

/**
* Creates a predicate that tests whether an element is a member of a collection.
*
* If the collection is empty, the predicate will be false.
* @param elem Element
* @param collection Expression
* @return is-member predicate
*/
<E, C extends Collection<E>> Predicate isMember(E elem, Expression<C> collection);

/**
* Creates a predicate that tests whether an element is not a member of a collection.
*
* If the collection is empty, the predicate will be true.
* @param elem Element
* @param collection Expression
* @return is-member predicate
*/
<E, C extends Collection<E>> Predicate isNotMember(E elem, Expression<C> collection);

/**
* Create a negation of the given restriction.
* @param restriction restriction expression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ simpleConditionalExpression
: comparisonExpression
| likeExpression
| inExpression
| memberOfExpression
;

inExpression
Expand All @@ -78,9 +79,13 @@ literal
;

likeExpression
: stringExpression ('NOT')? LIKE whereClauseValue
: stringExpression (NOT)? LIKE whereClauseValue
;

memberOfExpression
: inItem (NOT)? MEMBEROF whereClauseParam
;

comparisonExpression
: stringExpression COMPARISON_OPERATOR stringExpression
| simpleArithmeticExpression COMPARISON_OPERATOR simpleArithmeticExpression
Expand Down Expand Up @@ -182,6 +187,8 @@ LIKE: 'LIKE' ;

IN: 'IN' ;

MEMBEROF: 'MEMBER OF' ;

COMPARISON_OPERATOR: '>' | '<' | '>=' | '<=' | '=' | '<>' | '!=' ;

DOT: '.' ;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cz.cvut.kbss.jopa.exception;

import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;

/**
* Indicates an error during parsing and translation of SOQL to SPARQL.
*/
public class SoqlException extends OWLPersistenceException {

public SoqlException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,39 @@
package cz.cvut.kbss.jopa.query.criteria;

import cz.cvut.kbss.jopa.model.CriteriaQueryImpl;
import cz.cvut.kbss.jopa.model.query.criteria.*;
import cz.cvut.kbss.jopa.query.criteria.expressions.*;
import cz.cvut.kbss.jopa.model.query.criteria.Expression;
import cz.cvut.kbss.jopa.model.query.criteria.Order;
import cz.cvut.kbss.jopa.model.query.criteria.ParameterExpression;
import cz.cvut.kbss.jopa.model.query.criteria.Path;
import cz.cvut.kbss.jopa.model.query.criteria.Predicate;
import cz.cvut.kbss.jopa.query.criteria.expressions.AbsFunction;
import cz.cvut.kbss.jopa.query.criteria.expressions.AbstractExpression;
import cz.cvut.kbss.jopa.query.criteria.expressions.AbstractPathExpression;
import cz.cvut.kbss.jopa.query.criteria.expressions.CeilFunction;
import cz.cvut.kbss.jopa.query.criteria.expressions.CountFunction;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionEqualImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionGreaterThanImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionGreaterThanOrEqualImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionInImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionLessThanImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionLessThanOrEqualImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionLikeImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionLiteralImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionNotEqualImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ExpressionNotLikeImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.FloorFunction;
import cz.cvut.kbss.jopa.query.criteria.expressions.IsMemberExpression;
import cz.cvut.kbss.jopa.query.criteria.expressions.LangFunction;
import cz.cvut.kbss.jopa.query.criteria.expressions.LengthFunction;
import cz.cvut.kbss.jopa.query.criteria.expressions.LowerFunction;
import cz.cvut.kbss.jopa.query.criteria.expressions.OrderImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.ParameterExpressionImpl;
import cz.cvut.kbss.jopa.query.criteria.expressions.UpperFunction;
import cz.cvut.kbss.jopa.sessions.CriteriaBuilder;
import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl;

import java.util.Arrays;
import java.util.Collection;

public class CriteriaBuilderImpl implements CriteriaBuilder {

Expand Down Expand Up @@ -225,6 +252,18 @@ public <T> In<T> notIn(Expression<? extends T> expression) {
return inExpression;
}

@Override
public <E, C extends Collection<E>> Predicate isMember(E elem, Expression<C> collection) {
return new IsMemberExpression<>(elem, collection, this);
}

@Override
public <E, C extends Collection<E>> Predicate isNotMember(E elem, Expression<C> collection) {
final IsMemberExpression<E> expr = new IsMemberExpression<>(elem, collection, this);
expr.not();
return expr;
}

@Override
public <Y extends Comparable<? super Y>> Predicate greaterThan(Expression<? extends Y> x,
Expression<? extends Y> y) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import cz.cvut.kbss.jopa.model.metamodel.Bindable;
import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification;
import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
import cz.cvut.kbss.jopa.model.metamodel.TypesSpecification;
import cz.cvut.kbss.jopa.model.query.criteria.Path;
import cz.cvut.kbss.jopa.query.criteria.expressions.AbstractPathExpression;
import cz.cvut.kbss.jopa.sessions.CriteriaBuilder;
Expand All @@ -34,6 +35,9 @@ public PathImpl(Metamodel metamodel, AbstractPathExpression pathSource, FieldSpe
}

private static <E> Class<E> resolveBindableJavaType(FieldSpecification<?, ?> attribute) {
if (attribute instanceof TypesSpecification) {
return ((TypesSpecification) attribute).getElementType();
}
assert attribute instanceof Bindable;
return ((Bindable<E>) attribute).getBindableJavaType();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/**
* Copyright (C) 2023 Czech Technical University in Prague
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* <p>
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. You should have received a copy of the GNU General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
package cz.cvut.kbss.jopa.query.criteria.expressions;

Expand All @@ -27,7 +25,8 @@ public abstract class AbstractPathExpression<X> extends AbstractExpression<X> im
protected AbstractPathExpression pathSource;
protected final Metamodel metamodel;

public AbstractPathExpression(Class<X> type, AbstractPathExpression pathSource, Metamodel metamodel, CriteriaBuilder cb) {
public AbstractPathExpression(Class<X> type, AbstractPathExpression pathSource, Metamodel metamodel,
CriteriaBuilder cb) {
super(type, cb);
this.pathSource = pathSource;
this.metamodel = metamodel;
Expand All @@ -38,6 +37,8 @@ public <Y> Path<Y> getAttr(String attributeName) {
final FieldSpecification<? super X, ?> fs;
if (et.getIdentifier().getName().equals(attributeName)) {
fs = et.getIdentifier();
} else if (et.getTypes() != null && et.getTypes().getName().equals(attributeName)) {
fs = et.getTypes();
} else {
fs = et.getAttribute(attributeName);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cz.cvut.kbss.jopa.query.criteria.expressions;

import cz.cvut.kbss.jopa.model.query.criteria.Expression;
import cz.cvut.kbss.jopa.model.query.criteria.Predicate;
import cz.cvut.kbss.jopa.query.criteria.AbstractPredicate;
import cz.cvut.kbss.jopa.query.criteria.CriteriaParameterFiller;
import cz.cvut.kbss.jopa.query.soql.SoqlConstants;
import cz.cvut.kbss.jopa.sessions.CriteriaBuilder;

import java.util.Collection;
import java.util.List;

public class IsMemberExpression<Y> extends AbstractPredicate {

private final Expression<? extends Collection<Y>> collectionExpression;
private final Y value;

public IsMemberExpression(Y value, Expression<? extends Collection<Y>> collectionExpression, CriteriaBuilder cb) {
super(BooleanOperator.AND, cb);
this.value = value;
this.collectionExpression = collectionExpression;
}

@Override
public Predicate not() {
super.negate();
return this;
}

@Override
public List<Expression<Boolean>> getExpressions() {
return List.of(this);
}

@Override
public void setExpressionToQuery(StringBuilder query, CriteriaParameterFiller parameterFiller) {
final AbstractExpression<?> param = (AbstractExpression<?>) cb.literal(value);
param.setExpressionToQuery(query, parameterFiller);
if (negated) {
query.append(' ').append(SoqlConstants.NOT);
}
query.append(' ').append(SoqlConstants.MEMBER_OF).append(' ');
((AbstractExpression<?>) collectionExpression).setExpressionToQuery(query, parameterFiller);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cz.cvut.kbss.jopa.query.soql;

/**
* SOQL ({@code NOT}) {@code MEMBER OF} operator.
*/
public class MemberOfOperator implements FilterableExpression {

@Override
public String toFilterExpression(String parameter, String value) {
return "";
}

@Override
public boolean requiresFilterExpression() {
return false;
}

static MemberOfOperator memberOf() {
return new MemberOfOperator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package cz.cvut.kbss.jopa.query.soql;

import cz.cvut.kbss.jopa.query.sparql.SparqlConstants;
import cz.cvut.kbss.jopa.utils.IdentifierTransformer;

import java.util.Collections;
Expand Down Expand Up @@ -162,6 +163,7 @@ public String getBasicGraphPattern(String rootVariable) {
}

private static String toIri(SoqlNode node) {
return IdentifierTransformer.stringifyIri(node.getIri());
final String nodeIri = node.getIri();
return SparqlConstants.RDF_TYPE_SHORTCUT.equals(nodeIri) ? nodeIri : IdentifierTransformer.stringifyIri(nodeIri);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public class SoqlConstants {
*/
public static final String IN = "IN";

/**
* {@code MEMBER OF} operator.
*/
public static final String MEMBER_OF = "MEMBER OF";

/**
* {@code NOT} operator.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
*/
package cz.cvut.kbss.jopa.query.soql;

import cz.cvut.kbss.jopa.exception.SoqlException;
import cz.cvut.kbss.jopa.model.MetamodelImpl;
import cz.cvut.kbss.jopa.model.metamodel.Attribute;
import cz.cvut.kbss.jopa.model.metamodel.EntityType;
import cz.cvut.kbss.jopa.model.metamodel.IdentifiableEntityType;
import cz.cvut.kbss.jopa.model.metamodel.PluralAttribute;
import cz.cvut.kbss.jopa.model.metamodel.SingularAttribute;
import cz.cvut.kbss.jopa.model.metamodel.Type;
import cz.cvut.kbss.jopa.query.sparql.SparqlConstants;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTree;
Expand Down Expand Up @@ -366,6 +368,22 @@ public void exitLikeExpression(SoqlParser.LikeExpressionContext ctx) {
this.isInObjectIdentifierExpression = false;
}

@Override
public void enterMemberOfExpression(SoqlParser.MemberOfExpressionContext ctx) {

}

@Override
public void exitMemberOfExpression(SoqlParser.MemberOfExpressionContext ctx) {
if (ctx.getChildCount() > 2 && ctx.getChild(1).getText().equals(SoqlConstants.NOT)) {
attrPointer.setNot(true);
}
attrPointer.setOperator(MemberOfOperator.memberOf());
ParseTree whereClauseValue = ctx.getChild(0);
attrPointer.setValue(whereClauseValue.getText());
this.isInObjectIdentifierExpression = false;
}

@Override
public void enterComparisonExpression(SoqlParser.ComparisonExpressionContext ctx) {
}
Expand Down Expand Up @@ -689,14 +707,24 @@ private IdentifiableEntityType<?> getEntityType(String name) {
}

private void setAllNodesIris(EntityType<?> entityType, SoqlNode node) {
if (entityType.getIdentifier().getName().equals(node.getValue())) {
final String nodeName = node.getValue();
if (entityType.getIdentifier().getName().equals(nodeName)) {
return;
}
final Attribute<?, ?> abstractAttribute = entityType.getAttribute(node.getValue());
if (entityType.getTypes() != null && entityType.getTypes().getName().equals(node.getValue())) {
node.setIri(SparqlConstants.RDF_TYPE_SHORTCUT);
return;
}
final Attribute<?, ?> att;
try {
att = entityType.getAttribute(node.getValue());
} catch (IllegalArgumentException e) {
throw new SoqlException("No matching attribute with name '" + node.getValue() + "' found on entity type '" + entityType.getName() + "'.");
}
//not implemented case of 3 or more fragments (chained SoqlNodes)
node.setIri(abstractAttribute.getIRI().toString());
node.setIri(att.getIRI().toString());
if (node.hasChild()) {
final Type<?> type = resolveBindableType(abstractAttribute);
final Type<?> type = resolveBindableType(att);
if (type.getPersistenceType() != Type.PersistenceType.ENTITY) {
return;
}
Expand Down
Loading