Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1223,10 +1223,20 @@ public TermAst termFromConstraint(fr.inria.corese.core.next.impl.parser.antlr.Sp

public TermAst termFromBuiltInCall(fr.inria.corese.core.next.impl.parser.antlr.SparqlParser.BuiltInCallContext ctx) {
if (ctx.existsFunc() != null) {
return new ExistsAst(popCapturedExistsPattern());
} else if (ctx.notExistsFunc() != null) {
return new NotExistsAst(popCapturedExistsPattern());
} else if (ctx.regexExpression() != null) {
GroupGraphPatternAst existsPattern = popCapturedExistsPattern();
if (existsPattern == null) {
throw new QueryEvaluationException("EXISTS { ... } inner pattern was not captured; check listener order");
}
return new ExistsAst(existsPattern);
}
if (ctx.notExistsFunc() != null) {
GroupGraphPatternAst notExistsPattern = popCapturedExistsPattern();
if (notExistsPattern == null) {
throw new QueryEvaluationException("NOT EXISTS { ... } inner pattern was not captured; check listener order");
}
return new NotExistsAst(notExistsPattern);
}
if (ctx.regexExpression() != null) {
return termFromRegex(ctx.regexExpression());
} else if (ctx.strReplaceExpression() != null) {
return termFromReplace(ctx.strReplaceExpression());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package fr.inria.corese.core.next.query.impl.sparql.ast.constraint;

import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.GroupGraphPatternAst;

import java.util.Objects;

/**
* Operator {@code EXISTS { ... }} in SPARQL 1.1 FILTER
* SPARQL 1.1 {@code EXISTS { pattern }} in a {@code FILTER} (and elsewhere an expression is allowed).
* Evaluates whether the pattern has a solution given the current binding.
*/
public record ExistsAst(GroupGraphPatternAst pattern) implements ConstraintAst {
public record ExistsAst(GroupGraphPatternAst pattern) implements BooleanExpressionAst {

public ExistsAst {
Objects.requireNonNull(pattern, "pattern");
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package fr.inria.corese.core.next.query.impl.sparql.ast.constraint;

import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.GroupGraphPatternAst;

import java.util.Objects;

/**
* Operator {@code NOT EXISTS { ... }} in SPARQL 1.1 FILTER
* SPARQL 1.1 {@code NOT EXISTS { pattern }} in a {@code FILTER}.
* Semantically equivalent to applying {@code fn:not} to {@link ExistsAst} on the same pattern.
*/
public record NotExistsAst(GroupGraphPatternAst pattern) implements ConstraintAst {
public record NotExistsAst(GroupGraphPatternAst pattern) implements BooleanExpressionAst {

public NotExistsAst {
Objects.requireNonNull(pattern, "pattern");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.inria.corese.core.next.query.impl.parser;

import fr.inria.corese.core.next.query.impl.sparql.ast.*;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -1305,6 +1304,52 @@ void shouldParseNotExistsFilter() {
assertFalse(notExistsAst.pattern().patterns().isEmpty());
}

@Test
void shouldParseNotOverExistsFilter() {
SparqlParser parser = newParserDefault();

QueryAst ast = parser.parse("""
SELECT * WHERE {
?s ?p ?o .
FILTER(!EXISTS { ?s ex:email ?e })
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question, why a ! here ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say that it's to test Not over Exists, and to make sure the parser accepts FILTER(!EXISTS{}. In the future when we evaluate the SPARQL query it should give the same result as FILTER NOT EXISTS {}, but it does not produce the same AST

}
""");

assertNotNull(ast);
FilterAst filterAst = (FilterAst) ast.whereClause().patterns().getLast();
assertInstanceOf(BooleanNotAst.class, filterAst.operator());

BooleanNotAst booleanNotAst = (BooleanNotAst) filterAst.operator();
assertInstanceOf(ExistsAst.class, booleanNotAst.getArgument());

ExistsAst existsAst = (ExistsAst) booleanNotAst.getArgument();
assertNotNull(existsAst.pattern());
assertFalse(existsAst.pattern().patterns().isEmpty());
}

@Test
void shouldParseNotOverNotExistsFilter() {
SparqlParser parser = newParserDefault();

QueryAst ast = parser.parse("""
SELECT * WHERE {
?s ?p ?o .
FILTER(!NOT EXISTS { ?s ex:email ?e })
}
""");

assertNotNull(ast);
FilterAst filterAst = (FilterAst) ast.whereClause().patterns().getLast();
assertInstanceOf(BooleanNotAst.class, filterAst.operator());

BooleanNotAst booleanNotAst = (BooleanNotAst) filterAst.operator();
assertInstanceOf(NotExistsAst.class, booleanNotAst.getArgument());

NotExistsAst notExistsAst = (NotExistsAst) booleanNotAst.getArgument();
assertNotNull(notExistsAst.pattern());
assertFalse(notExistsAst.pattern().patterns().isEmpty());
}

@Test
void shouldParseExistsWithMultipleTriples() {
SparqlParser parser = newParserDefault();
Expand Down
Loading