blob: 905ed34ec5a20b841ebeea67b93f7d132a5d2b4f [file] [log] [blame]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*/
package org.apache.jena.dboe.storage;
import java.util.Iterator;
import java.util.stream.Stream;
import static org.apache.jena.atlas.iterator.Iter.*;
import org.apache.jena.atlas.iterator.Iter;
import org.apache.jena.dboe.storage.system.StorageLib;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.Quad;
/**
* A minimal interface for RDF storage. This is less that {@link DatasetGraph} or any of it's
* derived classes and it just concerned with {@link Triple}s and {@link Quad}s, not
* {@link Graph}s nor prefixes.
* <p>
* Storage is split into the triples for the default graph and quads for the named graphs.
* In {@link #find(Node, Node, Node, Node)} ({@code find} on the named graphs),
* {@code null} for the graph slot does not match the default graph.
* <p>
* <b>Concrete and Pattern Operations.</b>
* </p>
* <p>
* Various API operations work on "concrete" terms. For example, {@code add}. These are
* marked "concrete operation" in their javadoc. They are not matching operations. A
* concrete term is one of a URI, blank node or literal. It is not {@code null},
* {@code Node#ANY} nor a named variable. Any {@code Triple} or {@code Quad} must be
* composed of concrete terms.
* <p>
* A pattern operation is one where the arguments are concrete terms or wildcard
* {@code ANY}. Such an operation will match zero or more triples or quads.
* Any {@code Triple} or {@code Quad} can use {@code.ANY}.
* <p>Pattern operations do not match named variables.
* Using {@code Node#ANY} rather than {@code null} is preferred in pattern operations but
* both are acceptable.
*/
public interface StorageRDF {
/** Add a triple to the default graph.
* <p>Concrete operation.
*/
public default void add(Triple triple)
{ add(triple.getSubject(), triple.getPredicate(), triple.getObject()); }
/** Add a quad.
* <p>Concrete operation.
*/
public default void add(Quad quad)
{ add(quad.getGraph(), quad.getSubject(), quad.getPredicate(), quad.getObject()); }
/** Delete a triple from the default graph.
* <p>Concrete operation.
*/
public default void delete(Triple triple)
{ delete(triple.getSubject(), triple.getPredicate(), triple.getObject()); }
/** Delete a quad from the default graph. All terms are concrete, and not {@code Node#ANY}.
* For delete-by-pattern, see {@link #removeAll(Node, Node, Node, Node)}.
* <p>Concrete operation.
*/
public default void delete(Quad quad)
{ delete(quad.getGraph(), quad.getSubject(), quad.getPredicate(), quad.getObject()); }
/** Add a triple to the default graph.
* <p>Concrete operation.
*/
public void add(Node s, Node p, Node o);
/** Add to a named graph.
* <p>Concrete operation.
*/
public void add(Node g, Node s, Node p, Node o);
/**
* Delete from the default graph. {@code s}, {@code p}, {@code o} are all concrete.
* <p>Concrete operation.
* <p>See {@link #removeAll(Node, Node, Node)} for remove by pattern.
*/
public void delete(Node s, Node p, Node o);
/**
* Delete from a named graph. {@code s}, {@code p}, {@code o} are all concrete.
* <p>Concrete operation.
* <p>See {@link #removeAll(Node, Node, Node, Node)} for remove by pattern.
*/
public void delete(Node g, Node s, Node p, Node o);
/** Delete all triples matching a {@code find}-like pattern.
* <p>Pattern operation.
*/
public default void removeAll(Node s, Node p, Node o) { StorageLib.removeTriples(this, s, p, o); }
/** Delete all quads matching a {@code find}-like pattern.
* <p>Pattern operation.
*/
public default void removeAll(Node g, Node s, Node p, Node o) { StorageLib.removeTriples(this, s, p, o); }
/* Stream vs Iterator.
* Yes.
* Streams are nicer but they come with a performance cost. They create small intermediate objects.
* "find" operations are an important performance point and in API use often return one triple;
* the costs of a stream are a potential issue.
*
* Currently:
* stream(...) are streams.
* find(...) are iterators.
*/
// // ??
// /** Find in the default graph - return as quads (graph name {@link Quad#defaultGraphIRI}) */
// default Stream<Quad> streamDftGraph(Node s, Node p, Node o) {
// return stream(s, p, o).map(t -> Quad.create(Quad.defaultGraphIRI, t));
// Iterator<Quad> findDftGraph(
// return Iter.map(storage.find(s, p, o), t -> Quad.create(Quad.defaultGraphIRI, t));
// }
//
/** Find in the union graph (union of all named graphs, not the default graph).
* An RDF graph is a set of triples - the union graph does not shows duplicates even
* if more than one named graph contains a given triple.
* @implNote
* The default implementation of this operation involves the use of {@link Stream#distinct()}
* which is a <i><a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">stateful
* intermediate operation</a></i>. Without additional internal knowledge,
* it is necessary to remember all triples in the stream
* so far to know whether the next triple is a duplicate or not.
* This can be a significant amount of intermediate space.
* <p>
* An implementation may be able to exploit its internal representation to
* means that this operation can be implemented more efficient, for example,
* knowing that duplicate triples (same triple, from different graphs) will
* be adjacent in the stream so not requires the full cost of {@code distinct}
* to remove duplicates.
* <p>Pattern operation.
*/
public default Iterator<Triple> findUnionGraph(Node s, Node p, Node o) {
return distinct(
map(find(Node.ANY, s, p, o), Quad::asTriple)
);
}
/** Find in named graphs: does not look in the default graph.
* <p>Pattern operation.
*/
public default Iterator<Quad> find(Quad quad) {
return find(quad.getGraph(), quad.getSubject(), quad.getPredicate(), quad.getObject());
}
/** Find in named graphs: does not look in the default graph.
* <p>Pattern operation.
*/
public Iterator<Quad> find(Node g, Node s, Node p, Node o);
/** Find in the default graph.
* <p>Pattern operation.
*/
public default Iterator<Triple> find(Triple triple) {
return find(triple.getSubject(), triple.getPredicate(), triple.getObject());
}
/** Find in the default graph.
* <p>Pattern operation.
*/
public Iterator<Triple> find(Node s, Node p, Node o);
/** See {@link #findUnionGraph}.
* <p>Pattern operation.
*/
public default Stream<Triple> streamUnionGraph(Node s, Node p, Node o) {
return stream(Node.ANY, s, p, o).map(Quad::asTriple).distinct();
}
/** Find in named graphs: does not look in the default graph.
* <p>Pattern operation.
*/
public default Stream<Quad> stream(Quad quad) {
return stream(quad.getGraph(), quad.getSubject(), quad.getPredicate(), quad.getObject());
}
/** Find in named graphs: does not look in the default graph.
* <p>Pattern operation.
*/
public default Stream<Quad> stream(Node g, Node s, Node p, Node o) {
// Root of stream operation.
return Iter.asStream(find(g, s, p, o));
}
/** Find in the default graph.
* <p>Pattern operations.
*/
public default Stream<Triple> stream(Triple triple) {
return stream(triple.getSubject(), triple.getPredicate(), triple.getObject());
}
/** Find in the default graph.
* <p>Pattern operation.
*/
public default Stream<Triple> stream(Node s, Node p, Node o) {
// Root of stream operations.
return Iter.asStream(find(s, p, o));
}
// Leave one "contains" for triple and quads as abstract, to suggest direct implementation.
/** Test whether the default graph contains the triple.
* <p>Pattern operation.
* <p>Equivalent to {@code find(triple).hasNext()} or {@code stream(triple).findAny().isPresent()}.
*/
public default boolean contains(Triple triple) {
return contains(triple.getSubject(), triple.getPredicate(), triple.getObject());
}
/** Test whether the default graph contains the triple.
* <p>Pattern operation.
* <p>Equivalent to {@code find(s,p,o).hasNext()}.
*/
public boolean contains(Node s, Node p, Node o);
/** Test whether any named graph matches the quad.
* <p>Pattern operation.
* <p>Equivalent to {@code find(quad).hasNext()} or {@code stream(quad).findAny().isPresent()}.
*/
public default boolean contains(Quad quad) {
return contains(quad.getGraph(), quad.getSubject(), quad.getPredicate(), quad.getObject());
}
/** Test whether any named graph matches the quad.
* <p>Pattern operation.
* <p>Equivalent to {@code find(g,s,p,o).hasNext()}.
*/
boolean contains(Node g, Node s, Node p, Node o);
}