diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlListenerDispatcher.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlListenerDispatcher.java
index 327b66be5..8849fb3fb 100644
--- a/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlListenerDispatcher.java
+++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlListenerDispatcher.java
@@ -302,4 +302,14 @@ public void enterCreate(SparqlParser.CreateContext ctx) {
public void exitCreate(SparqlParser.CreateContext ctx) {
for (var d : delegates) d.exitCreate(ctx);
}
+
+ @Override
+ public void enterDrop(SparqlParser.DropContext ctx) {
+ for (var d : delegates) d.enterDrop(ctx);
+ }
+
+ @Override
+ public void exitDrop(SparqlParser.DropContext ctx) {
+ for (var d : delegates) d.exitDrop(ctx);
+ }
}
diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlQueryAnalyzer.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlQueryAnalyzer.java
index 372982ca7..a4c845f75 100644
--- a/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlQueryAnalyzer.java
+++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlQueryAnalyzer.java
@@ -160,6 +160,7 @@ private QueryAst buildAst(
SparqlListenerDispatcher updateListener = new SparqlListenerDispatcher(List.of(
new ClearUpdateAstListener(updateBuilder),
new CreateUpdateAstListener(updateBuilder),
+ new DropUpdateAstListener(updateBuilder),
new LoadUpdateAstListener(updateBuilder),
new BgpAstListener(updateBuilder),
new BindAstListener(updateBuilder),
diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlUpdateAstBuilder.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlUpdateAstBuilder.java
index ac4270542..4a77a2031 100644
--- a/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlUpdateAstBuilder.java
+++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/SparqlUpdateAstBuilder.java
@@ -58,6 +58,19 @@ public ClearRequestAst cleartoAst(SparqlParser.ClearContext ctx) {
}
}
+ public DropRequestAst dropToAst(SparqlParser.DropContext ctx) {
+ GraphRefAst targetGraphRef = null;
+ boolean silentFlag = ctx.SILENT() != null;
+ if (ctx.graphRefAll() != null) {
+ targetGraphRef = this.graphRefFromGraphRefAll(ctx.graphRefAll());
+ }
+ if (targetGraphRef != null) {
+ return new DropRequestAst(targetGraphRef, silentFlag);
+ } else {
+ throw new QueryEvaluationException("No target graph reference found in DROP query");
+ }
+ }
+
public CreateRequestAst createToAst(SparqlParser.CreateContext ctx) {
boolean silentFlag = ctx.SILENT() != null;
if (ctx.graphRef() != null) {
diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/listener/DropUpdateAstListener.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/listener/DropUpdateAstListener.java
new file mode 100644
index 000000000..e12b2bf8e
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/listener/DropUpdateAstListener.java
@@ -0,0 +1,20 @@
+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.SparqlUpdateAstBuilder;
+import fr.inria.corese.core.next.query.impl.sparql.ast.DropRequestAst;
+
+/**
+ * AST feature listener for DROP SPARQL update query
+ */
+public class DropUpdateAstListener extends AbstractSparqlUpdateAstListener {
+ public DropUpdateAstListener(SparqlUpdateAstBuilder builder) {
+ super(builder);
+ }
+
+ @Override
+ public void enterDrop(SparqlParser.DropContext ctx) {
+ DropRequestAst dropRequestAst = this.updateBuilder().dropToAst(ctx);
+ this.updateBuilder().addRequest(dropRequestAst);
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DropRequestAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DropRequestAst.java
new file mode 100644
index 000000000..bf071d511
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DropRequestAst.java
@@ -0,0 +1,24 @@
+package fr.inria.corese.core.next.query.impl.sparql.ast;
+
+import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor;
+
+/**
+ * Represents the DROP operation as defined in the SPARQL 1.1 recommendation.
+ * @param graphRef targeted graph to be dropped
+ * @param silent Determine if the resolution of the query must be resolved silently or not.
+ */
+public record DropRequestAst(GraphRefAst graphRef, boolean silent) implements UpdateRequestUnitAst {
+ /**
+ * Construct DROP query with a silent flag to false.
+ * @param graphRef targeted graph to be dropped
+ */
+ public DropRequestAst(GraphRefAst graphRef) {
+ this(graphRef, false);
+ }
+
+ @Override
+ public void accept(AstVisitor visitor) {
+ visitor.visit(this);
+ this.graphRef.accept(visitor);
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java
index e68694223..52dc6ca05 100644
--- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java
+++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java
@@ -5,5 +5,5 @@
/**
* Root interface for all operations related to the SPARQL Update operations listed in SPARQL 1.1 Update.
*/
-public sealed interface UpdateRequestUnitAst extends VisitableAst permits LoadRequestAst, ClearRequestAst, CreateRequestAst {
+public sealed interface UpdateRequestUnitAst extends VisitableAst permits LoadRequestAst, ClearRequestAst, CreateRequestAst, DropRequestAst {
}
diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserDropQueryTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserDropQueryTest.java
new file mode 100644
index 000000000..267334da7
--- /dev/null
+++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserDropQueryTest.java
@@ -0,0 +1,215 @@
+package fr.inria.corese.core.next.query.impl.parser;
+
+import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException;
+import fr.inria.corese.core.next.query.impl.parser.QueryParser;
+import fr.inria.corese.core.next.query.impl.sparql.ast.DropRequestAst;
+import fr.inria.corese.core.next.query.impl.sparql.ast.IriAst;
+import fr.inria.corese.core.next.query.impl.sparql.ast.QueryAst;
+import fr.inria.corese.core.next.query.impl.sparql.ast.UpdateRequestAst;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class SparqlParserDropQueryTest extends AbstractSparqlParserFeatureTest {
+
+ @Test
+ @DisplayName("should parse DROP GRAPH ")
+ void graphQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP GRAPH
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ IriAst graphIri = dropQueryAst.graphRef().graph();
+ assertEquals("", graphIri.raw());
+ assertFalse(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse DROP SILENT GRAPH and set the silent flag")
+ void graphSilentQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP SILENT GRAPH
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ IriAst graphIri = dropQueryAst.graphRef().graph();
+ assertEquals("", graphIri.raw());
+ assertTrue(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse DROP NAMED")
+ void namedQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP NAMED
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ assertTrue(dropQueryAst.graphRef().named());
+ assertFalse(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse DROP SILENT NAMED and set the silent flag")
+ void namedSilentQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP SILENT NAMED
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ assertTrue(dropQueryAst.graphRef().named());
+ assertTrue(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse DROP DEFAULT")
+ void defaultQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP DEFAULT
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ assertTrue(dropQueryAst.graphRef().defaultGraph());
+ assertFalse(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse DROP SILENT DEFAULT and set the silent flag")
+ void defaultSilentQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP SILENT DEFAULT
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ assertTrue(dropQueryAst.graphRef().defaultGraph());
+ assertTrue(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse DROP ALL")
+ void allQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP ALL
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ assertTrue(dropQueryAst.graphRef().all());
+ assertFalse(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse DROP SILENT ALL and set the silent flag")
+ void allSilentQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP SILENT ALL
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ assertInstanceOf(UpdateRequestAst.class, queryAst);
+ UpdateRequestAst updateRequestAst = (UpdateRequestAst) queryAst;
+ assertEquals(1, updateRequestAst.operations().size());
+ assertInstanceOf(DropRequestAst.class, updateRequestAst.operations().getFirst());
+ DropRequestAst dropQueryAst = (DropRequestAst) updateRequestAst.operations().getFirst();
+ assertNotNull(dropQueryAst.graphRef());
+ assertTrue(dropQueryAst.graphRef().all());
+ assertTrue(dropQueryAst.silent());
+ }
+
+ @Test
+ @DisplayName("should parse two chained DROP operations separated by ';'")
+ void chainedDropShouldCreateTwoUpdateOperations() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP GRAPH ;
+ DROP SILENT GRAPH
+ """;
+
+ QueryAst queryAst = parser.parse(query);
+ UpdateRequestAst update = assertInstanceOf(UpdateRequestAst.class, queryAst);
+ assertEquals(2, update.operations().size());
+
+ DropRequestAst first = assertInstanceOf(DropRequestAst.class, update.operations().getFirst());
+ assertEquals("", first.graphRef().graph().raw());
+ assertFalse(first.silent());
+
+ DropRequestAst second = assertInstanceOf(DropRequestAst.class, update.operations().get(1));
+ assertEquals("", second.graphRef().graph().raw());
+ assertTrue(second.silent());
+ }
+
+ @Test
+ @DisplayName("should keep the prologue when DROP uses a prefixed graph name")
+ void dropMustKeepItsPrologue() {
+ QueryParser parser = newParserDefault();
+ QueryAst ast = parser.parse("PREFIX ex: DROP GRAPH ex:g");
+ UpdateRequestAst update = assertInstanceOf(UpdateRequestAst.class, ast);
+
+ assertEquals(1, update.operations().size());
+ assertInstanceOf(DropRequestAst.class, update.operations().getFirst());
+ assertNotNull(update.prologue());
+ assertEquals(1, update.prologue().prefixDeclarations().size());
+ }
+
+ @Test
+ @DisplayName("should reject invalid DROP syntax with multiple graph references")
+ void failingTooManyQueryTest() {
+ QueryParser parser = newParserDefault();
+ String query = """
+ DROP SILENT ALL NAMED GRAPH
+ """;
+
+ assertThrows(QuerySyntaxException.class, () -> parser.parse(query));
+ }
+}