RDF4JTemplateTests.java
/*******************************************************************************
* Copyright (c) 2021 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.spring.support;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
import java.util.Set;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.model.vocabulary.FOAF;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.sparqlbuilder.constraint.propertypath.builder.PropertyPathBuilder;
import org.eclipse.rdf4j.sparqlbuilder.rdf.Rdf;
import org.eclipse.rdf4j.spring.RDF4JSpringTestBase;
import org.eclipse.rdf4j.spring.dao.exception.IncorrectResultSetSizeException;
import org.eclipse.rdf4j.spring.dao.support.opbuilder.UpdateExecutionBuilder;
import org.eclipse.rdf4j.spring.dao.support.sparql.NamedSparqlSupplier;
import org.eclipse.rdf4j.spring.domain.dao.ArtistDao;
import org.eclipse.rdf4j.spring.domain.dao.PaintingDao;
import org.eclipse.rdf4j.spring.domain.model.Artist;
import org.eclipse.rdf4j.spring.domain.model.EX;
import org.eclipse.rdf4j.spring.domain.model.Painting;
import org.eclipse.rdf4j.spring.util.QueryResultUtils;
import org.eclipse.rdf4j.spring.util.TypeMappingUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Florian Kleedorfer
* @since 4.0.0
*/
public class RDF4JTemplateTests extends RDF4JSpringTestBase {
@Autowired
private RDF4JTemplate rdf4JTemplate;
// used for checks
@Autowired
private ArtistDao artistDao;
@Autowired
PaintingDao paintingDao;
@Test
public void testUpdate1() {
UpdateExecutionBuilder updateBuilder = rdf4JTemplate.update(
String.format("INSERT { <%s> a <%s> } WHERE {} ", EX.of("Vermeer"), EX.Artist));
updateBuilder.execute();
Value type = rdf4JTemplate.tupleQuery(
String.format("SELECT ?type WHERE { <%s> a ?type }",
EX.of("Vermeer")))
.evaluateAndConvert()
.toSingleton(bs -> bs.getBinding("type").getValue());
Assertions.assertTrue(type.isIRI());
Assertions.assertEquals(EX.Artist.toString(), type.toString());
}
@Test
public void testUpdate1RepeatUpdate() {
testUpdate1();
testUpdate1();
testUpdate1();
testUpdate1();
testUpdate1();
}
@Test
public void testUpdate3() {
UpdateExecutionBuilder updateBuilder = rdf4JTemplate.update(getClass(), "createVermeer",
() -> String.format("INSERT { <%s> a <%s> } WHERE {} ", EX.of("Vermeer"), EX.Artist));
updateBuilder.execute();
Value type = rdf4JTemplate.tupleQuery(
String.format("SELECT ?type WHERE { <%s> a ?type }",
EX.of("Vermeer")))
.evaluateAndConvert()
.toSingleton(bs -> bs.getBinding("type").getValue());
Assertions.assertTrue(type.isIRI());
Assertions.assertEquals(EX.Artist.toString(), type.toString());
}
@Test
public void testUpdateFromResource() {
UpdateExecutionBuilder updateBuilder = rdf4JTemplate.updateFromResource(getClass(),
"classpath:sparql/insert-vermeer.rq");
updateBuilder.execute();
Value type = rdf4JTemplate.tupleQuery(
String.format("SELECT ?type WHERE { <%s> a ?type }",
EX.of("Vermeer")))
.evaluateAndConvert()
.toSingleton(bs -> bs.getBinding("type").getValue());
Assertions.assertTrue(type.isIRI());
Assertions.assertEquals(EX.Artist.toString(), type.toString());
}
@Test
public void testUpdate2() {
UpdateExecutionBuilder updateBuilder = rdf4JTemplate.update(getClass(),
NamedSparqlSupplier.of("addVermeer",
() -> String.format("INSERT { <%s> a <%s> } WHERE {} ", EX.of("Vermeer"), EX.Artist)));
updateBuilder.execute();
Value type = rdf4JTemplate.tupleQuery(
String.format("SELECT ?type "
+ "WHERE { <%s> a ?type }",
EX.of("Vermeer")))
.evaluateAndConvert()
.toSingleton(bs -> bs.getBinding("type").getValue());
Assertions.assertTrue(type.isIRI());
Assertions.assertEquals(EX.Artist.toString(), type.toString());
}
@Test
public void testUpdateWithoutCachingStatement() {
UpdateExecutionBuilder updateBuilder = rdf4JTemplate.updateWithoutCachingStatement(
String.format("INSERT { <%s> a <%s> } "
+ "WHERE {} ", EX.of("Vermeer"), EX.Artist));
updateBuilder.execute();
Value type = rdf4JTemplate.tupleQuery(
String.format("SELECT ?type "
+ "WHERE { <%s> a ?type }",
EX.of("Vermeer")))
.evaluateAndConvert()
.toSingleton(bs -> bs.getBinding("type").getValue());
Assertions.assertTrue(type.isIRI());
Assertions.assertEquals(EX.Artist.toString(), type.toString());
}
@Test
public void testUpdateWithBuilder() {
rdf4JTemplate.updateWithBuilder()
.subject(EX.of("Vermeer"))
.add(RDF.TYPE, EX.Artist)
.execute();
Value type = rdf4JTemplate.tupleQuery(
String.format("SELECT ?type WHERE { <%s> a ?type }",
EX.of("Vermeer")))
.evaluateAndConvert()
.toSingleton(bs -> bs.getBinding("type").getValue());
Assertions.assertTrue(type.isIRI());
Assertions.assertEquals(EX.Artist.toString(), type.toString());
}
@Test
public void testTupleQuery() {
Set<IRI> artists = rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?artist "
+ "WHERE { ?artist a ex:Artist }")
.evaluateAndConvert()
.toSet(bs -> QueryResultUtils.getIRI(bs, "artist"));
Assertions.assertEquals(2, artists.size());
Assertions.assertTrue(artists.contains(EX.Picasso));
Assertions.assertTrue(artists.contains(EX.VanGogh));
}
@Test
public void testTupleQueryParametrized() {
Set<IRI> artists = rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?artist "
+ "WHERE { ?artist a ?type }")
.withBinding("type", EX.Artist)
.evaluateAndConvert()
.toSet(bs -> QueryResultUtils.getIRI(bs, "artist"));
Assertions.assertEquals(2, artists.size());
Assertions.assertTrue(artists.contains(EX.Picasso));
Assertions.assertTrue(artists.contains(EX.VanGogh));
}
@Test
public void testTupleQueryRepeatQuery() {
testTupleQuery();
testTupleQuery();
testTupleQuery();
testTupleQuery();
testTupleQuery();
}
@Test
public void tupleQuery3() {
Set<IRI> artists = rdf4JTemplate.tupleQuery(getClass(), "readArtists",
() -> "PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?artist "
+ "WHERE { ?artist a ex:Artist }")
.evaluateAndConvert()
.toSet(bs -> QueryResultUtils.getIRI(bs, "artist"));
Assertions.assertEquals(2, artists.size());
Assertions.assertTrue(artists.contains(EX.Picasso));
Assertions.assertTrue(artists.contains(EX.VanGogh));
}
@Test
public void testTupleQueryFromResource() {
Set<IRI> artists = rdf4JTemplate.tupleQueryFromResource(getClass(), "classpath:sparql/get-artists.rq")
.evaluateAndConvert()
.toSet(bs -> QueryResultUtils.getIRI(bs, "artist"));
Assertions.assertEquals(2, artists.size());
Assertions.assertTrue(artists.contains(EX.Picasso));
Assertions.assertTrue(artists.contains(EX.VanGogh));
}
@Test
public void testTupleQuery2() {
Set<IRI> artists = rdf4JTemplate.tupleQuery(getClass(),
NamedSparqlSupplier.of("getArtists", () -> "PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?artist "
+ "WHERE { ?artist a ex:Artist }"))
.evaluateAndConvert()
.toSet(bs -> QueryResultUtils.getIRI(bs, "artist"));
Assertions.assertEquals(2, artists.size());
Assertions.assertTrue(artists.contains(EX.Picasso));
Assertions.assertTrue(artists.contains(EX.VanGogh));
}
@Test
public void testGraphQuery() {
Model model = rdf4JTemplate.graphQuery("PREFIX ex: <http://example.org/>"
+ "CONSTRUCT { ?a ?p ?o } "
+ "WHERE { ?a a ex:Artist; ?p ?o }")
.evaluateAndConvert()
.toModel();
checkArtistModel(model);
}
@Test
public void graphQueryRepeatedly() {
for (int i = 0; i < 20; i++) {
testGraphQuery();
}
}
protected void checkArtistModel(Model model) {
Assertions.assertTrue(
model.contains(
EX.Picasso,
FOAF.SURNAME,
SimpleValueFactory.getInstance().createLiteral("Picasso")));
Assertions.assertTrue(
model.contains(
EX.Picasso,
FOAF.FIRST_NAME,
SimpleValueFactory.getInstance().createLiteral("Pablo")));
Assertions.assertTrue(
model.contains(
EX.VanGogh,
FOAF.FIRST_NAME,
SimpleValueFactory.getInstance().createLiteral("Vincent")));
Assertions.assertTrue(
model.contains(
EX.VanGogh,
EX.creatorOf,
EX.starryNight));
}
@Test
public void testGraphQuery3() {
Model model = rdf4JTemplate.graphQuery(
getClass(),
"getArtistStarshapedGraphs",
() -> "PREFIX ex: <http://example.org/>"
+ "CONSTRUCT { ?a ?p ?o } "
+ "WHERE { ?a a ex:Artist; ?p ?o }")
.evaluateAndConvert()
.toModel();
checkArtistModel(model);
}
@Test
public void testGraphQueryFromResource() {
Model model = rdf4JTemplate.graphQueryFromResource(getClass(), "classpath:sparql/construct-artists.rq")
.evaluateAndConvert()
.toModel();
checkArtistModel(model);
}
@Test
public void testGraphQuery2() {
Model model = rdf4JTemplate.graphQuery(
getClass(),
NamedSparqlSupplier.of("getArtistStarshapedGraphs",
() -> "PREFIX ex: <http://example.org/>"
+ "CONSTRUCT { ?a ?p ?o } "
+ "WHERE { ?a a ex:Artist; ?p ?o }"))
.evaluateAndConvert()
.toModel();
checkArtistModel(model);
}
@Test
public void testDeleteTriplesWithSubject() {
rdf4JTemplate.deleteTriplesWithSubject(EX.guernica);
Assertions.assertTrue(
rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?a "
+ "WHERE { ?a a ex:Painting . FILTER (?a = ex:guernica) }")
.evaluateAndConvert()
.toList(bs -> bs.getValue("a"))
.isEmpty());
Assertions.assertFalse(
rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?a "
+ "WHERE { ?a ?p ?o . FILTER (?o = ex:guernica) }")
.evaluateAndConvert()
.toList(bs -> bs.getValue("a"))
.isEmpty());
}
@Test
public void testDelete() {
rdf4JTemplate.delete(EX.guernica);
Assertions.assertTrue(
rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?a "
+ "WHERE { ?a a ex:Painting . FILTER (?a = ex:guernica) }")
.evaluateAndConvert()
.toList(bs -> bs.getValue("a"))
.isEmpty());
Assertions.assertTrue(
rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?a "
+ "WHERE { ?a ?p ?o . FILTER (?o = ex:guernica) }")
.evaluateAndConvert()
.toList(bs -> bs.getValue("a"))
.isEmpty());
}
@Test
public void testDelete2() {
Assertions.assertFalse(
rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?a "
+ "WHERE { ?a ?b ?c . "
+ " FILTER (?a = ex:guernica "
+ " || ?c = ex:guernica) "
+ "}")
.evaluateAndConvert()
.toList(bs -> bs.getValue("a"))
.isEmpty());
rdf4JTemplate.delete(EX.Picasso,
List.of(
PropertyPathBuilder
.of(Rdf.iri(EX.creatorOf))
.build()
));
Assertions.assertTrue(
rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?a "
+ "WHERE { ?a ?b ?c . "
+ " FILTER (?a = ex:guernica "
+ " || ?a = ex:Picasso"
+ " || ?c = ex:guernica"
+ " || ?c = ex:Picasso) "
+ "}")
.evaluateAndConvert()
.toList(bs -> bs.getValue("a"))
.isEmpty());
Assertions.assertFalse(rdf4JTemplate.tupleQuery("PREFIX ex: <http://example.org/>"
+ "SELECT distinct ?a "
+ "WHERE { ?a ?b ?c . "
+ " FILTER (?a = ex:starryNight "
+ " || ?a = ex:VanGogh"
+ " || ?c = ex:starryNight"
+ " || ?c = ex:VanGogh) "
+ "}")
.evaluateAndConvert()
.toList(bs -> bs.getValue("a"))
.isEmpty());
}
@Test
public void testAssociate_deleteIncoming() {
IRI me = EX.of("me");
rdf4JTemplate.updateWithBuilder()
.subject(me)
.add(RDF.TYPE, EX.Artist)
.execute();
// let's forge some data
rdf4JTemplate.associate(
me,
EX.creatorOf,
Set.of(EX.guernica, EX.starryNight, EX.potatoEaters),
false, true);
Assertions.assertTrue(
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", EX.Picasso)
.evaluateAndConvert()
.toList(b -> b)
.isEmpty());
Assertions.assertEquals(1,
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", EX.VanGogh)
.evaluateAndConvert()
.toList(b -> b)
.size());
Assertions.assertEquals(3,
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", me)
.evaluateAndConvert()
.toList(b -> b)
.size());
}
@Test
public void testAssociate_deleteOutgoing() {
rdf4JTemplate.associate(
EX.Picasso,
EX.creatorOf,
Set.of(EX.starryNight, EX.potatoEaters),
true, false);
Assertions.assertEquals(2,
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", EX.Picasso)
.evaluateAndConvert()
.toList(b -> b)
.size());
Assertions.assertEquals(3,
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", EX.VanGogh)
.evaluateAndConvert()
.toList(b -> b)
.size());
}
@Test
public void testDeleteWithPropertyPaths() {
int triplesBeforeDelete = countTriples();
Artist picasso = artistDao.getById(EX.Picasso);
assertNotNull(picasso);
Painting guernica = paintingDao.getById(EX.guernica);
assertNotNull(guernica);
rdf4JTemplate.delete(EX.Picasso, List.of(PropertyPathBuilder.of(EX.creatorOf).build()));
assertThrows(IncorrectResultSetSizeException.class, () -> artistDao.getById(EX.Picasso));
assertThrows(IncorrectResultSetSizeException.class, () -> paintingDao.getById(EX.guernica));
assertEquals(triplesBeforeDelete - 8, countTriples());
}
@Test
public void testDeleteWithDisjunctivePropertyPaths() {
int triplesBeforeDelete = countTriples();
Artist picasso = artistDao.getById(EX.Picasso);
assertNotNull(picasso);
Painting guernica = paintingDao.getById(EX.guernica);
assertNotNull(guernica);
rdf4JTemplate.delete(EX.Picasso, List.of(PropertyPathBuilder.of(EX.creatorOf).or(EX.homeAddress).build()));
assertThrows(IncorrectResultSetSizeException.class, () -> artistDao.getById(EX.Picasso));
assertThrows(IncorrectResultSetSizeException.class, () -> paintingDao.getById(EX.guernica));
assertEquals(triplesBeforeDelete - 11, countTriples());
}
@Test
public void testDeleteWithMultiplePropertyPaths() {
int triplesBeforeDelete = countTriples();
Artist picasso = artistDao.getById(EX.Picasso);
assertNotNull(picasso);
Painting guernica = paintingDao.getById(EX.guernica);
assertNotNull(guernica);
rdf4JTemplate.delete(EX.Picasso,
List.of(PropertyPathBuilder.of(EX.creatorOf).build(), PropertyPathBuilder.of(EX.homeAddress).build()));
assertThrows(IncorrectResultSetSizeException.class, () -> artistDao.getById(EX.Picasso));
assertThrows(IncorrectResultSetSizeException.class, () -> paintingDao.getById(EX.guernica));
assertEquals(triplesBeforeDelete - 11, countTriples());
}
@Test
public void testDeleteWithLongerPropertyPaths() {
int triplesBeforeDelete = countTriples();
Artist picasso = artistDao.getById(EX.Picasso);
assertNotNull(picasso);
Painting guernica = paintingDao.getById(EX.guernica);
assertNotNull(guernica);
// deletes guernica and the home address, but not picasso
rdf4JTemplate.delete(EX.guernica,
List.of(PropertyPathBuilder.of(EX.creatorOf).inv().then(EX.homeAddress).build()));
picasso = artistDao.getById(EX.Picasso);
assertNotNull(picasso);
assertThrows(IncorrectResultSetSizeException.class, () -> paintingDao.getById(EX.guernica));
assertEquals(triplesBeforeDelete - 8, countTriples());
}
@Test
public void testAssociate() {
IRI me = EX.of("me");
rdf4JTemplate.updateWithBuilder()
.subject(me)
.add(RDF.TYPE, EX.Artist)
.execute();
// let's forge some data
rdf4JTemplate.associate(
me,
EX.creatorOf,
Set.of(EX.guernica, EX.starryNight, EX.potatoEaters),
false, false);
Assertions.assertEquals(1,
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", EX.Picasso)
.evaluateAndConvert()
.toList(b -> b)
.size());
Assertions.assertEquals(3,
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", EX.VanGogh)
.evaluateAndConvert()
.toList(b -> b)
.size());
Assertions.assertEquals(3,
rdf4JTemplate.tupleQueryFromResource(getClass(),
"classpath:sparql/get-paintings-of-artist.rq")
.withBinding("artist", me)
.evaluateAndConvert()
.toList(b -> b)
.size());
}
private int countTriples() {
return this.rdf4JTemplate
.tupleQuery("SELECT (count(*) AS ?count) WHERE { ?a ?b ?c }")
.evaluateAndConvert()
.toSingletonOfWholeResult(result -> {
BindingSet bs = result.next();
return TypeMappingUtils.toInt(QueryResultUtils.getValue(bs, "count"));
});
}
}