diff --git a/core/sparqlbuilder/src/main/java/org/eclipse/rdf4j/sparqlbuilder/graphpattern/GroupGraphPattern.java b/core/sparqlbuilder/src/main/java/org/eclipse/rdf4j/sparqlbuilder/graphpattern/GroupGraphPattern.java index 31870505fd..21a5d4e248 100644 --- a/core/sparqlbuilder/src/main/java/org/eclipse/rdf4j/sparqlbuilder/graphpattern/GroupGraphPattern.java +++ b/core/sparqlbuilder/src/main/java/org/eclipse/rdf4j/sparqlbuilder/graphpattern/GroupGraphPattern.java @@ -58,7 +58,14 @@ protected void copy(GroupGraphPattern original) { @Override public GroupGraphPattern and(GraphPattern... patterns) { if (isEmpty() && patterns.length == 1 && (isGGP(patterns[0]))) { - copy(GraphPatterns.extractOrConvertToGGP(patterns[0])); + GroupGraphPattern ggp = GraphPatterns.extractOrConvertToGGP(patterns[0]); + // Only copy if it's a plain GroupGraphPattern, not a specialized subclass + // like FilterExistsGraphPattern or MinusGraphPattern which override getQueryString() + if (ggp.getClass() == GroupGraphPattern.class) { + copy(ggp); + } else { + addElements(patterns); + } } else { addElements(patterns); } diff --git a/core/sparqlbuilder/src/test/java/org/eclipse/rdf4j/sparqlbuilder/core/query/ModifyQueryTest.java b/core/sparqlbuilder/src/test/java/org/eclipse/rdf4j/sparqlbuilder/core/query/ModifyQueryTest.java index fe272f7bf5..babe79ec0f 100644 --- a/core/sparqlbuilder/src/test/java/org/eclipse/rdf4j/sparqlbuilder/core/query/ModifyQueryTest.java +++ b/core/sparqlbuilder/src/test/java/org/eclipse/rdf4j/sparqlbuilder/core/query/ModifyQueryTest.java @@ -17,6 +17,7 @@ import org.eclipse.rdf4j.sparqlbuilder.core.SparqlBuilder; import org.eclipse.rdf4j.sparqlbuilder.core.Variable; import org.eclipse.rdf4j.sparqlbuilder.examples.BaseExamples; +import org.eclipse.rdf4j.sparqlbuilder.graphpattern.GraphPatternNotTriples; import org.eclipse.rdf4j.sparqlbuilder.graphpattern.GraphPatterns; import org.eclipse.rdf4j.sparqlbuilder.graphpattern.TriplePattern; import org.eclipse.rdf4j.sparqlbuilder.rdf.Iri; @@ -53,4 +54,68 @@ public void example_issue_1481() { "WHERE { OPTIONAL { ?subject ?predicate . }\n" + "OPTIONAL { ?subject ?object . } }"); } + + @Test + public void example_broken_filter_not_exists() { + // given + Iri subjectIri = iri("http://my-example.com/anyIRI/"); + Iri classIri = iri("http://my-example.com/SomeClass/"); + TriplePattern triple = subjectIri.isA(classIri); + + String queryString = Queries.MODIFY() + .insert(triple) + .where(GraphPatterns.filterNotExists(triple)) + .getQueryString(); + + assertEquals("INSERT { a . }\n" + + // the WHERE clause is incorrectly generated: + // "WHERE { a . }", + // should be: + "WHERE { FILTER NOT EXISTS { a . } }", + queryString + ); + } + + @Test + public void test_GraphPatternNotTriples_getQueryString() { + // given + Iri subjectIri = iri("http://my-example.com/anyIRI/"); + Iri classIri = iri("http://my-example.com/SomeClass/"); + TriplePattern triple = subjectIri.isA(classIri); + + String queryString = GraphPatterns.filterNotExists(triple).getQueryString(); + + assertEquals( + "FILTER NOT EXISTS { a . }", + queryString + ); + } + + @Test + public void test_GraphPatterns_and_getQueryString() { + GraphPatternNotTriples actual = GraphPatterns.and(); + assertEquals("{}", actual.getQueryString()); + } + + @Test + public void test_GraphPatterns_and_FilterExistsGraphPattern_getQueryString() { + + TriplePattern triple = iri("http://my-example.com/anyIRI/").isA(iri("http://my-example.com/SomeClass/")); + + // emptyGraphPattern by itself yields "{}", see test_GraphPatterns_and_getQueryString + GraphPatternNotTriples emptyGraphPattern = GraphPatterns.and(); + + // filterNotExists by itself yields "FILTER NOT EXISTS { ... }", see test_GraphPatternNotTriples_getQueryString + GraphPatternNotTriples filterNotExists = GraphPatterns.filterNotExists(triple); + + // this is the cause oft the failing example_broken_filter_not_exists test + GraphPatternNotTriples withFilterNotExists = emptyGraphPattern.and(filterNotExists); + + String actual = withFilterNotExists.getQueryString(); + + assertEquals( + "{ FILTER NOT EXISTS { a . } }", + actual + ); + } }