SubselectTest.java
/*******************************************************************************
* Copyright (c) 2022 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.testsuite.sparql.tests;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.QueryResults;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.testsuite.sparql.AbstractComplianceTest;
import org.junit.jupiter.api.DynamicTest;
/**
* Tests on SPARQL nested SELECT query handling.
*
* @author Jeen Broekstra
*/
public class SubselectTest extends AbstractComplianceTest {
public SubselectTest(Supplier<Repository> repo) {
super(repo);
}
private void testSES2373SubselectOptional(RepositoryConnection conn) {
conn.prepareUpdate(QueryLanguage.SPARQL,
"insert data {" + "<u:1> <u:r> <u:subject> ." + "<u:1> <u:v> 1 ." + "<u:1> <u:x> <u:x1> ."
+ "<u:2> <u:r> <u:subject> ." + "<u:2> <u:v> 2 ." + "<u:2> <u:x> <u:x2> ."
+ "<u:3> <u:r> <u:subject> ." + "<u:3> <u:v> 3 ." + "<u:3> <u:x> <u:x3> ."
+ "<u:4> <u:r> <u:subject> ." + "<u:4> <u:v> 4 ." + "<u:4> <u:x> <u:x4> ."
+ "<u:5> <u:r> <u:subject> ." + "<u:5> <u:v> 5 ." + "<u:5> <u:x> <u:x5> ." + "}")
.execute();
String qb = "select ?x { \n" +
" { select ?v { ?v <u:r> <u:subject> filter (?v = <u:1>) } }.\n" +
" optional { select ?val { ?v <u:v> ?val .} }\n" +
" ?v <u:x> ?x \n" +
"}\n";
TupleQuery tq = conn.prepareTupleQuery(QueryLanguage.SPARQL, qb);
try (TupleQueryResult result = tq.evaluate()) {
assertTrue(result.hasNext(), "The query should return a result");
BindingSet b = result.next();
assertTrue(b.hasBinding("x"), "?x is from the mandatory part of the query and should be bound");
}
}
private void testSES2154SubselectOptional(RepositoryConnection conn) {
String ub = "insert data { \n" +
" <urn:s1> a <urn:C> . \n" +
" <urn:s2> a <urn:C> . \n" +
" <urn:s3> a <urn:C> . \n" +
" <urn:s4> a <urn:C> . \n" +
" <urn:s5> a <urn:C> . \n" +
" <urn:s6> a <urn:C> . \n" +
" <urn:s7> a <urn:C> . \n" +
" <urn:s8> a <urn:C> . \n" +
" <urn:s9> a <urn:C> . \n" +
" <urn:s10> a <urn:C> . \n" +
" <urn:s11> a <urn:C> . \n" +
" <urn:s12> a <urn:C> . \n" +
" <urn:s1> <urn:p> \"01\" . \n" +
" <urn:s2> <urn:p> \"02\" . \n" +
" <urn:s3> <urn:p> \"03\" . \n" +
" <urn:s4> <urn:p> \"04\" . \n" +
" <urn:s5> <urn:p> \"05\" . \n" +
" <urn:s6> <urn:p> \"06\" . \n" +
" <urn:s7> <urn:p> \"07\" . \n" +
" <urn:s8> <urn:p> \"08\" . \n" +
" <urn:s9> <urn:p> \"09\" . \n" +
" <urn:s10> <urn:p> \"10\" . \n" +
" <urn:s11> <urn:p> \"11\" . \n" +
" <urn:s12> <urn:p> \"12\" . \n" +
"} \n";
conn.prepareUpdate(QueryLanguage.SPARQL, ub).execute();
String qb = "SELECT ?s ?label\n" +
"WHERE { \n" +
" ?s a <urn:C> \n .\n" +
" OPTIONAL { {SELECT ?label WHERE { \n" +
" ?s <urn:p> ?label . \n" +
" } ORDER BY ?label LIMIT 2 \n" +
" }\n" +
" }\n" +
"}\n" +
"ORDER BY ?s\n" +
"LIMIT 10 \n";
TupleQuery tq = conn.prepareTupleQuery(QueryLanguage.SPARQL, qb);
try (TupleQueryResult evaluate = tq.evaluate()) {
assertTrue(evaluate.hasNext(), "The query should return a result");
List<BindingSet> result = QueryResults.asList(evaluate);
assertEquals(10, result.size());
for (BindingSet bs : result) {
Literal label = (Literal) bs.getValue("label");
assertTrue(label.stringValue().equals("01") || label.stringValue().equals("02"),
"wrong label value (expected '01' or '02', but got '" + label.stringValue() + "')");
}
}
}
public Stream<DynamicTest> tests() {
return Stream.of(makeTest("SES2373SubselectOptional", this::testSES2373SubselectOptional),
makeTest("SES2154SubselectOptional", this::testSES2154SubselectOptional));
}
}