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 @@ -65,8 +65,12 @@ public final class SparqlAstBuilder {
private ProjectionAst projection = ProjectionAsts.selectAll();

/**
* SELECT DISTINCT / REDUCED. Set by SelectQueryFeature when parsing SELECT (DISTINCT | REDUCED)? ...
* Dataset clause (FROM/FROM NAMED)
*/
private final Set<IriAst> datasetDefaultGraphs = new LinkedHashSet<>();
private final Set<IriAst> datasetNamedGraphs = new LinkedHashSet<>();

/** SELECT DISTINCT / REDUCED. Set by SelectQueryFeature when parsing SELECT (DISTINCT | REDUCED)? ... */
private boolean distinct;
private boolean reduced;

Expand Down Expand Up @@ -160,6 +164,14 @@ public void setReduced(boolean reduced) {
this.reduced = reduced;
}

public void addFromGraph(IriAst graph) {
this.datasetDefaultGraphs.add(graph);
}

public void addFromNamedGraph(IriAst graph) {
Comment thread
MaillPierre marked this conversation as resolved.
this.datasetNamedGraphs.add(graph);
}

/**
* Sets the LIMIT for pagination
*
Expand Down Expand Up @@ -280,13 +292,13 @@ public QueryAst getResult() {
if (whereClause == null) {
throw new IllegalStateException("No WHERE clause: did you call exitGroup() for the top-level GroupGraphPattern?");
}
DatasetClauseAst datasetClauseAst = new DatasetClauseAst(datasetDefaultGraphs, datasetNamedGraphs);
return switch (this.queryType) {
case ASK -> new AskQueryAst(whereClause);
case DESCRIBE -> new DescribeQueryAst(datasetClauseAst, describeResources, whereClause);
case CONSTRUCT -> null;
case DESCRIBE -> new DescribeQueryAst(describeResources, whereClause);
case SELECT -> new SelectQueryAst(projection, whereClause, buildSolutionModifier());
case UNDEFINED ->
throw new QueryEvaluationException("Could not determine the type of query during parsing");
case ASK -> new AskQueryAst(datasetClauseAst, whereClause);
case SELECT -> new SelectQueryAst(projection, datasetClauseAst, whereClause, buildSolutionModifier());
case UNDEFINED -> throw new QueryEvaluationException("Could not determine the type of query during parsing");
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,14 @@ public void enterDescribeQuery(SparqlParser.DescribeQueryContext ctx) {
public void exitDescribeQuery(SparqlParser.DescribeQueryContext ctx) {
for (var d : delegates) d.exitDescribeQuery(ctx);
}

@Override
public void exitDefaultGraphClause(SparqlParser.DefaultGraphClauseContext ctx) {
for (var d : delegates) d.exitDefaultGraphClause(ctx);
}

@Override
public void exitNamedGraphClause(SparqlParser.NamedGraphClauseContext ctx) {
for (var d : delegates) d.exitNamedGraphClause(ctx);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ public QueryAst parse(Reader reader, String baseIRI) {
new SolutionModifierFeature(builder),
new FilterFeature(builder),
new UnionFeature(builder),
new DescribeQueryFeature(builder)
new DescribeQueryFeature(builder),
new DatasetClauseFeature(builder)
));

walker.walk(listener, tree);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package fr.inria.corese.core.next.query.impl.parser.listener;

import fr.inria.corese.core.next.impl.parser.antlr.SparqlParser;
import fr.inria.corese.core.next.query.impl.parser.SparqlAstBuilder;
import fr.inria.corese.core.next.query.impl.sparql.ast.IriAst;

public class DatasetClauseFeature extends AbstractSparqlFeature {
public DatasetClauseFeature(SparqlAstBuilder builder) {
super(builder);
}

@Override
public void exitDefaultGraphClause(SparqlParser.DefaultGraphClauseContext ctx) {
builder().addFromGraph((IriAst) builder().termFromIriRef(ctx.sourceSelector().iriRef()));
}

@Override
public void exitNamedGraphClause(SparqlParser.NamedGraphClauseContext ctx) {
builder().addFromNamedGraph((IriAst) builder().termFromIriRef(ctx.sourceSelector().iriRef()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
* }
* }</pre>
*/
public record AskQueryAst(GroupGraphPatternAst whereClause) implements QueryAst {
public record AskQueryAst(DatasetClauseAst datasetClause, GroupGraphPatternAst whereClause) implements QueryAst {
public AskQueryAst {
if (whereClause == null) {
Comment thread
MaillPierre marked this conversation as resolved.
whereClause = new GroupGraphPatternAst(List.of());
}
if(datasetClause == null) {
datasetClause = DatasetClauseAst.none();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@
* triples are added to the output graph.
* </p>
*/
public record ConstructQueryAst(GroupGraphPatternAst constructTemplate, GroupGraphPatternAst whereClause) implements QueryAst {
public record ConstructQueryAst(DatasetClauseAst datasetClause, GroupGraphPatternAst constructTemplate, GroupGraphPatternAst whereClause) implements QueryAst {
public ConstructQueryAst {
if (constructTemplate == null) {
constructTemplate = new GroupGraphPatternAst(List.of());
}
if (whereClause == null) {
whereClause = new GroupGraphPatternAst(List.of());
}
if (datasetClause == null) {
datasetClause = DatasetClauseAst.none();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fr.inria.corese.core.next.query.impl.sparql.ast;

import java.util.LinkedHashSet;
import java.util.Set;

public record DatasetClauseAst(Set<IriAst> graphs, Set<IriAst> namedGraphs) {
Comment thread
MaillPierre marked this conversation as resolved.

public DatasetClauseAst {
graphs = graphs == null ? Set.of() : Set.copyOf(new LinkedHashSet<>(graphs));
namedGraphs = namedGraphs == null ? Set.of() : Set.copyOf(new LinkedHashSet<>(namedGraphs));
}

public static DatasetClauseAst none() {
return new DatasetClauseAst(Set.of(), Set.of());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
* }
* }</pre>
*/
public record DescribeQueryAst(List<TermAst> described, GroupGraphPatternAst whereClause) implements QueryAst {
public record DescribeQueryAst(DatasetClauseAst datasetClause, List<TermAst> described, GroupGraphPatternAst whereClause) implements QueryAst {
public DescribeQueryAst {
described = described != null ? List.copyOf(described) : List.of();
if (whereClause == null) {
whereClause = new GroupGraphPatternAst(List.of());
}
if(datasetClause == null) {
datasetClause = DatasetClauseAst.none();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
* Holds the WHERE clause as a group graph pattern; query-specific projection/template can be added later.
*/
public sealed interface QueryAst permits AskQueryAst, ConstructQueryAst, DescribeQueryAst, SelectQueryAst {
DatasetClauseAst datasetClause();
GroupGraphPatternAst whereClause();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@
* Abstract Syntax Tree (AST) representation of a SPARQL {@code SELECT} query.
* Holds the projection (SELECT * or SELECT ?v1 ?v2 ...) and the WHERE clause.
*/
public record SelectQueryAst(ProjectionAst projection, GroupGraphPatternAst whereClause, SolutionModifierAst solutionModifier) implements QueryAst {
public record SelectQueryAst(ProjectionAst projection, DatasetClauseAst datasetClause, GroupGraphPatternAst whereClause, SolutionModifierAst solutionModifier) implements QueryAst {

/** Constructor with default projection SELECT *. */
public SelectQueryAst(GroupGraphPatternAst whereClause) {
this(ProjectionAsts.selectAll(), whereClause);
this(ProjectionAsts.selectAll(), DatasetClauseAst.none(), whereClause);
}

/** Constructor with default solution modifier (no DISTINCT/REDUCED/ORDER BY/LIMIT/OFFSET). */
public SelectQueryAst(ProjectionAst projection, GroupGraphPatternAst whereClause) {
this(projection, whereClause, null);
public SelectQueryAst(ProjectionAst projection, DatasetClauseAst datasetClause, GroupGraphPatternAst whereClause) {
this(projection, datasetClause, whereClause, null);
}

public SelectQueryAst {
if (projection == null) {
projection = ProjectionAsts.selectAll();
}
if(datasetClause == null) {
datasetClause = DatasetClauseAst.none();
}
if (whereClause == null) {
whereClause = new GroupGraphPatternAst(List.of());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,32 +426,32 @@ void whereClauseAccessor() {
GroupGraphPatternAst where = new GroupGraphPatternAst(List.of(
new BgpAst(List.of(new TriplePatternAst(
new VarAst("s"), new VarAst("p"), new VarAst("o"))))));
QueryAst q = new AskQueryAst(where);
QueryAst q = new AskQueryAst(DatasetClauseAst.none(), where);
assertSame(where, q.whereClause());
}

@Test
@DisplayName("AskQueryAst record equality when same whereClause")
void askQueryAstEquality() {
GroupGraphPatternAst where = new GroupGraphPatternAst(List.of());
AskQueryAst a = new AskQueryAst(where);
AskQueryAst b = new AskQueryAst(where);
AskQueryAst a = new AskQueryAst(DatasetClauseAst.none(), where);
AskQueryAst b = new AskQueryAst(DatasetClauseAst.none(), where);
assertEquals(a, b);
assertEquals(a.hashCode(), b.hashCode());
}

@Test
@DisplayName("AskQueryAst with null whereClause uses empty group")
void nullWhereClauseDefaultsToEmpty() {
AskQueryAst q = new AskQueryAst(null);
AskQueryAst q = new AskQueryAst(DatasetClauseAst.none(), null);
assertNotNull(q.whereClause());
assertTrue(q.whereClause().patterns().isEmpty());
}

@Test
@DisplayName("AskQueryAst implements QueryAst")
void implementsQueryAst() {
assertInstanceOf(QueryAst.class, new AskQueryAst(new GroupGraphPatternAst(List.of())));
assertInstanceOf(QueryAst.class, new AskQueryAst(DatasetClauseAst.none(), new GroupGraphPatternAst(List.of())));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,15 @@ class NullSafety {
@Test
@DisplayName("null described list defaults to empty list")
void nullDescribedDefaultsToEmpty() {
DescribeQueryAst ast = new DescribeQueryAst(null, null);
DescribeQueryAst ast = new DescribeQueryAst(null,null, null);
assertNotNull(ast.described());
assertTrue(ast.described().isEmpty());
}

@Test
@DisplayName("null whereClause defaults to empty GroupGraphPatternAst")
void nullWhereClauseDefaultsToEmptyGroup() {
DescribeQueryAst ast = new DescribeQueryAst(null, null);
DescribeQueryAst ast = new DescribeQueryAst(null,null, null);
assertNotNull(ast.whereClause());
assertTrue(ast.whereClause().patterns().isEmpty());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,126 @@ public void shouldIgnoreCommentInTheMiddleOfQuery() {
assertInstanceOf(VarAst.class, bgpAst.triples().getLast().object());
assertEquals("o", ((VarAst)bgpAst.triples().getLast().object()).name());
}

@Test
@DisplayName("a list of From graphs can be inserted")
public void fromGraphs() {
SparqlParser parser = newParserDefault();
String commentedQuery = """
ASK
FROM <http://ns.inria.fr/graph>
WHERE {
?s a ?c ;
<http://ns.inria.fr/test#property> ?o .
}
""";
QueryAst queryAst = parser.parse(commentedQuery);
assertNotNull(queryAst);
assertNotNull(queryAst.datasetClause());
assertNotNull(queryAst.datasetClause().graphs());
assertEquals(1, queryAst.datasetClause().graphs().size());
assertInstanceOf(IriAst.class, queryAst.datasetClause().graphs().toArray()[0]);
assertNotNull(queryAst.datasetClause().namedGraphs());
assertEquals(0, queryAst.datasetClause().namedGraphs().size());
}

@Test
@DisplayName("a list of From graphs can be inserted")
public void fromMultipleGraphs() {
SparqlParser parser = newParserDefault();
String commentedQuery = """
ASK
FROM <http://ns.inria.fr/graph1>
FROM <http://ns.inria.fr/graph2>
FROM <http://ns.inria.fr/graph3>
WHERE {
?s a ?c ;
<http://ns.inria.fr/test#property> ?o .
}
""";
QueryAst queryAst = parser.parse(commentedQuery);
assertNotNull(queryAst);
assertNotNull(queryAst.datasetClause());
assertNotNull(queryAst.datasetClause().graphs());
assertEquals(3, queryAst.datasetClause().graphs().size());
assertInstanceOf(IriAst.class, queryAst.datasetClause().graphs().toArray()[0]);
assertInstanceOf(IriAst.class, queryAst.datasetClause().graphs().toArray()[1]);
assertInstanceOf(IriAst.class, queryAst.datasetClause().graphs().toArray()[2]);
assertNotNull(queryAst.datasetClause().namedGraphs());
assertEquals(0, queryAst.datasetClause().namedGraphs().size());
}

@Test
@DisplayName("a list of From graphs can be inserted")
public void fromNamedGraphs() {
SparqlParser parser = newParserDefault();
String commentedQuery = """
ASK
FROM NAMED <http://ns.inria.fr/graph>
WHERE {
?s a ?c ;
<http://ns.inria.fr/test#property> ?o .
}
""";
QueryAst queryAst = parser.parse(commentedQuery);
assertNotNull(queryAst);
assertNotNull(queryAst.datasetClause());
assertNotNull(queryAst.datasetClause().namedGraphs());
assertEquals(1, queryAst.datasetClause().namedGraphs().size());
assertInstanceOf(IriAst.class, queryAst.datasetClause().namedGraphs().toArray()[0]);
assertNotNull(queryAst.datasetClause().graphs());
assertEquals(0, queryAst.datasetClause().graphs().size());
}

@Test
@DisplayName("a list of From graphs can be inserted")
public void fromMultipleNamedGraphs() {
SparqlParser parser = newParserDefault();
String commentedQuery = """
ASK
FROM NAMED <http://ns.inria.fr/graph1>
FROM NAMED <http://ns.inria.fr/graph2>
FROM NAMED <http://ns.inria.fr/graph3>
WHERE {
?s a ?c ;
<http://ns.inria.fr/test#property> ?o .
}
""";
QueryAst queryAst = parser.parse(commentedQuery);
assertNotNull(queryAst);
assertNotNull(queryAst.datasetClause());
assertNotNull(queryAst.datasetClause().graphs());
assertNotNull(queryAst.datasetClause().namedGraphs());
assertEquals(3, queryAst.datasetClause().namedGraphs().size());
assertInstanceOf(IriAst.class, queryAst.datasetClause().namedGraphs().toArray()[0]);
assertInstanceOf(IriAst.class, queryAst.datasetClause().namedGraphs().toArray()[1]);
assertInstanceOf(IriAst.class, queryAst.datasetClause().namedGraphs().toArray()[2]);
assertEquals(0, queryAst.datasetClause().graphs().size());
}

@Test
@DisplayName("a list of From graphs can be inserted")
public void fromMultipleMixedGraphs() {
SparqlParser parser = newParserDefault();
String commentedQuery = """
ASK
FROM <http://ns.inria.fr/graph1>
FROM NAMED <http://ns.inria.fr/graph2>
FROM <http://ns.inria.fr/graph3>
WHERE {
?s a ?c ;
<http://ns.inria.fr/test#property> ?o .
}
""";
QueryAst queryAst = parser.parse(commentedQuery);
assertNotNull(queryAst);
assertNotNull(queryAst.datasetClause());
assertNotNull(queryAst.datasetClause().graphs());
assertEquals(2, queryAst.datasetClause().graphs().size());
assertInstanceOf(IriAst.class, queryAst.datasetClause().graphs().toArray()[0]);
assertInstanceOf(IriAst.class, queryAst.datasetClause().graphs().toArray()[1]);
assertNotNull(queryAst.datasetClause().namedGraphs());
assertEquals(1, queryAst.datasetClause().namedGraphs().size());
assertInstanceOf(IriAst.class, queryAst.datasetClause().namedGraphs().toArray()[0]);
}
}
Loading
Loading