diff --git a/s-pipes-core/src/main/java/cz/cvut/spipes/function/time/AddDaysDeprecated.java b/s-pipes-core/src/main/java/cz/cvut/spipes/function/time/AddDaysDeprecated.java
new file mode 100644
index 00000000..24bec3d9
--- /dev/null
+++ b/s-pipes-core/src/main/java/cz/cvut/spipes/function/time/AddDaysDeprecated.java
@@ -0,0 +1,75 @@
+package cz.cvut.spipes.function.time;
+
+import cz.cvut.spipes.constants.KBSS_TIMEF;
+import cz.cvut.spipes.function.ValueFunction;
+import org.apache.jena.datatypes.RDFDatatype;
+import org.apache.jena.datatypes.xsd.XSDDatatype;
+import org.apache.jena.datatypes.xsd.impl.XSDBaseStringType;
+import org.apache.jena.datatypes.xsd.impl.XSDDateType;
+import org.apache.jena.graph.Node;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.apache.jena.sparql.function.FunctionEnv;
+import org.topbraid.spin.arq.AbstractFunction2;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeParseException;
+import java.util.Optional;
+
+/**
+ * Extend specified `date` by number of `days`. Return typed literal with same datatype.
+ * Currently, supports only xsd:date datatype.
+ */
+public class AddDaysDeprecated extends AbstractFunction2 implements ValueFunction {
+
+
+ private static final String TYPE_IRI = KBSS_TIMEF.uri + "add-days-deprecated";
+
+ @Override
+ public String getTypeURI() {
+ return TYPE_IRI;
+ }
+
+ @Override
+ protected NodeValue exec(Node date, Node days, FunctionEnv env) {
+
+ Long daysToAdd = getDays(days);
+ RDFDatatype datatype = getDatatype(date);
+
+ try {
+ if (datatype != null && daysToAdd != null) {
+ //TODO quite slow to parse everytime
+ String newDate = LocalDate.parse(date.getLiteral().getValue().toString()).plusDays(daysToAdd).toString();
+ return NodeValue.makeNode(newDate, datatype);
+ }
+ } catch (DateTimeParseException e){
+ }
+
+ return null;
+ }
+
+ private Long getDays(Node days) {
+ return Optional.of(days)
+ .filter(Node::isLiteral)
+ .filter(n -> n.getLiteralValue() instanceof Integer)
+ .map(n -> ((Integer) n.getLiteralValue()).longValue())
+ .orElse(null);
+ }
+
+ RDFDatatype getDatatype(Node date) {
+
+ return Optional.of(date)
+ .filter(Node::isLiteral)
+ .map(n -> getNewDatatype(n.getLiteralDatatype()))
+ .orElse(null);
+ }
+
+ RDFDatatype getNewDatatype(RDFDatatype datatype){
+ if (datatype instanceof XSDDateType) {
+ return XSDDatatype.XSDdate;
+ }
+ if (datatype instanceof XSDBaseStringType) {
+ return XSDDatatype.XSDstring;
+ }
+ return null;
+ }
+}
diff --git a/s-pipes-core/src/test/java/cz/cvut/spin/SpinIntegrationTest.java b/s-pipes-core/src/test/java/cz/cvut/spin/SpinIntegrationTest.java
index bed44fc8..b689ee7f 100644
--- a/s-pipes-core/src/test/java/cz/cvut/spin/SpinIntegrationTest.java
+++ b/s-pipes-core/src/test/java/cz/cvut/spin/SpinIntegrationTest.java
@@ -1,42 +1,74 @@
package cz.cvut.spin;
-import cz.cvut.spipes.engine.PipelineFactory;
-import org.apache.jena.ontology.OntModelSpec;
-import org.apache.jena.query.*;
-import org.apache.jena.rdf.model.*;
-import org.apache.jena.util.FileUtils;
-import org.junit.jupiter.api.Test;
-import org.topbraid.spin.model.SPINFactory;
-import org.topbraid.spin.system.SPINModuleRegistry;
-import org.topbraid.spin.util.SPINExpressions;
-import org.topbraid.spin.vocabulary.SP;
+ import org.apache.jena.ontology.OntModelSpec;
+ import org.apache.jena.query.*;
+ import org.apache.jena.rdf.model.*;
+ import org.apache.jena.util.FileUtils;
+ import org.jetbrains.annotations.NotNull;
+ import org.junit.jupiter.api.Test;
+ import org.topbraid.spin.model.SPINFactory;
+ import org.topbraid.spin.system.SPINModuleRegistry;
+ import org.topbraid.spin.util.SPINExpressions;
+ import org.topbraid.spin.vocabulary.SP;
+
+ import java.io.InputStream;
+ import java.net.URLEncoder;
+ import java.nio.charset.StandardCharsets;
+
+ import static org.junit.jupiter.api.Assertions.assertEquals;
+ import static org.junit.jupiter.api.Assertions.assertTrue;
+
+ public class SpinIntegrationTest {
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
+ @Test
+ public void executeCustomSPINRDFFunctionWithinQuery() {
+ // load custom function definition from RDF
+ Model funcDefModel = getCustomSPINRDFFunctionModel();
-import static org.junit.jupiter.api.Assertions.assertEquals;
+ // register custom function
+ //SPINModuleRegistry.get().init();
+ SPINModuleRegistry.get().registerAll(funcDefModel, null);
-public class SpinIntegrationTest {
+ String repositoryUrl = "http://repository.org";
+ String graphId = "http://graphid.org";
+
+ String queryString = String.format("""
+ PREFIX kbss-spif:
+ SELECT ?sparqlServiceUrl
+ WHERE {
+ BIND(kbss-spif:create-sparql-service-url(
+ "%s",
+ "%s"
+ ) AS ?sparqlServiceUrl)
+ }
+ """, repositoryUrl, graphId);
+ Model model = ModelFactory.createDefaultModel();
- @Test
- public void executeSPINExpressionWithCustomSpinFunction() throws UnsupportedEncodingException {
+ Query query = QueryFactory.create(queryString);
+
+ QueryExecution qexec = QueryExecutionFactory.create(query, model);
+ ResultSet results = qexec.execSelect();
- // load custom function definition
- Model funcDefModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
- // Model funcDefModel = ModelFactory.createDefaultModel(); // TODO this does not work
+ assertTrue(results.hasNext(), "No results found");
- final InputStream funcDefIs = this.getClass().getResourceAsStream("/spin/spin-function.spin.ttl");
+ QuerySolution soln = results.nextSolution();
+ assertEquals(
+ soln.getResource("sparqlServiceUrl").getURI(),
+ constructServiceUrl(repositoryUrl, graphId)
+ );
- funcDefModel.read(funcDefIs, null, FileUtils.langTurtle);
+ }
+
+ @Test
+ public void executeSPINExpressionWithCustomSPINRDFFunction() {
+ // load custom function definition from RDF
+ Model funcDefModel = getCustomSPINRDFFunctionModel();
// register custom function
//SPINModuleRegistry.get().init();
SPINModuleRegistry.get().registerAll(funcDefModel, null);
-
-
+
// load custom function call
Model funcCallModel = ModelFactory.createDefaultModel();
@@ -51,20 +83,17 @@ public void executeSPINExpressionWithCustomSpinFunction() throws UnsupportedEnco
// evaluate SPIN expression
QuerySolutionMap bindings = new QuerySolutionMap();
String repositoryUrl = "http://repository.org";
- String reportGraphId = "http://graphid.org";
- bindings.add("repositoryUrl", ResourceFactory.createPlainLiteral(repositoryUrl));
- bindings.add("reportGraphId", ResourceFactory.createPlainLiteral(reportGraphId));
-
+ String graphId = "http://graphid.org";
+ bindings.add("sparqlEndpoint", ResourceFactory.createPlainLiteral(repositoryUrl));
+ bindings.add("defaultGraphUri", ResourceFactory.createPlainLiteral(graphId));
RDFNode node = SPINExpressions.evaluate(callExpr, callExpr.getModel(), bindings); //TODO resource.getModel() should be part o context
-
- assertEquals(node.toString(), repositoryUrl + "?default-graph-uri=" + URLEncoder.encode(reportGraphId, StandardCharsets.UTF_8) );
+ assertEquals(node.toString(), constructServiceUrl(repositoryUrl, graphId));
}
@Test
public void executeSPINQueryWithCustomJavaFunction() {
- PipelineFactory pipelineFactory = new PipelineFactory();
String queryString = """
PREFIX kbss-timef:
@@ -78,13 +107,30 @@ public void executeSPINQueryWithCustomJavaFunction() {
Query query = QueryFactory.create(queryString);
-
QueryExecution qexec = QueryExecutionFactory.create(query, model);
ResultSet results = qexec.execSelect();
- if (results.hasNext()) {
- QuerySolution soln = results.nextSolution();
- assertEquals(soln.getLiteral("nextDay").getString(), "2022-01-02");
- }
+ assertTrue(results.hasNext(), "No results found");
+
+ QuerySolution soln = results.nextSolution();
+ assertEquals(soln.getLiteral("nextDay").getString(), "2022-01-02");
}
+
+ @NotNull
+ private Model getCustomSPINRDFFunctionModel() {
+ // load custom function definition
+ Model funcDefModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
+ // Model funcDefModel = ModelFactory.createDefaultModel(); // TODO this does not work
+
+ final InputStream funcDefIs = this.getClass().getResourceAsStream("/spin/spin-function.spin.ttl");
+
+ funcDefModel.read(funcDefIs, null, FileUtils.langTurtle);
+
+ return funcDefModel;
+ }
+
+ @NotNull
+ private String constructServiceUrl(String repositoryUrl, String graphId) {
+ return String.format("%s?default-graph-uri=%s", repositoryUrl, URLEncoder.encode(graphId, StandardCharsets.UTF_8));
+ }
}
diff --git a/s-pipes-core/src/test/java/cz/cvut/spipes/function/time/AddDaysDeprecatedTest.java b/s-pipes-core/src/test/java/cz/cvut/spipes/function/time/AddDaysDeprecatedTest.java
new file mode 100644
index 00000000..0772a26f
--- /dev/null
+++ b/s-pipes-core/src/test/java/cz/cvut/spipes/function/time/AddDaysDeprecatedTest.java
@@ -0,0 +1,56 @@
+package cz.cvut.spipes.function.time;
+
+import org.apache.jena.datatypes.RDFDatatype;
+import org.apache.jena.datatypes.xsd.XSDDatatype;
+import org.apache.jena.graph.Node;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.jupiter.api.Test;
+
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class AddDaysDeprecatedTest {
+
+ @Test
+ public void execReturnsTimeFromPast() {
+
+ AddDaysDeprecated addDays = new AddDaysDeprecated();
+ Node date = getDateNode("2022-01-01").asNode();
+ Node days = NodeValue.makeNodeDecimal("-1").asNode();
+
+ NodeValue returnedDate = addDays.exec(date, days, null);
+
+ NodeValue expectedDate = getDateNode("2021-12-31");
+ assertEquals(expectedDate, returnedDate);
+ }
+
+ @Test
+ public void execReturnsDatatypeOfInputLiteral() {
+ Node days = NodeValue.makeNodeDecimal("1").asNode();
+
+ Stream.of(XSDDatatype.XSDdate, XSDDatatype.XSDstring).forEach(
+ dt -> {
+ Node date = getNode("2021-12-31", dt).asNode();
+
+ AddDaysDeprecated addDays = new AddDaysDeprecated();
+ NodeValue returnedDate = addDays.exec(date, days, null);
+
+ NodeValue expectedDate = getNode("2022-01-01", dt);
+ assertEquals(expectedDate, returnedDate);
+ });
+ }
+
+
+ private NodeValue getDateNode(String date){
+ return getNode(date, XSDDatatype.XSDdate);
+ }
+
+ private NodeValue getNode(String date, RDFDatatype datatype) {
+ return NodeValue.makeNode(
+ date,
+ null,
+ datatype.getURI()
+ );
+ }
+}
\ No newline at end of file
diff --git a/s-pipes-core/src/test/resources/spin/spin-function-call.ttl b/s-pipes-core/src/test/resources/spin/spin-function-call.ttl
index bf2859b8..26407b3f 100644
--- a/s-pipes-core/src/test/resources/spin/spin-function-call.ttl
+++ b/s-pipes-core/src/test/resources/spin/spin-function-call.ttl
@@ -16,12 +16,12 @@
.
[
- rdf:type kbss-spif:create-sparql-service-url ;
+ rdf:type kbss-spif:create-sparql-service-url-deprecated ;
sp:arg1 [
- sp:varName "repositoryUrl" ;
+ sp:varName "sparqlEndpoint" ;
] ;
sp:arg2 [
- sp:varName "reportGraphId" ;
+ sp:varName "defaultGraphUri" ;
] ;
]
.