You are viewing a plain text version of this content. The canonical link for it is here.
Posted to pr@jena.apache.org by GitBox <gi...@apache.org> on 2020/10/01 13:20:26 UTC

[GitHub] [jena] afs opened a new pull request #804: JENA-1974: G, a library of functions for working with Graph.

afs opened a new pull request #804:
URL: https://github.com/apache/jena/pull/804


   "G" is a set of functions for working with Graph at the detail triple level.
   
   It packages up the checking needed around, for example, "getOne" when the code is expecting exactly one match, not zero, not several. It is taken from original use in jena-shacl but is itself generally useful when working in Java walking data in graphs.
   
   There are some operations that are RDFS aware - these would be applicable for when RDFS reasoning is not enabled (in SHACL, certain parts of RDFS are required like transitive subclass but not full RDFS reasoning).
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] ajs6f commented on pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
ajs6f commented on pull request #804:
URL: https://github.com/apache/jena/pull/804#issuecomment-702148246


   This is useful stuff, and I have no objections by any means. Question: is this how you expect ideas for a new API to be presented? Via a "sidecar" library of functions like this? I'm inspired to ask because I see a number of things like "return a param or a default" which would make a lot of sense to impl via returning `Optional` from a hypothetical new graph abstraction.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] afs commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
afs commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r499551523



##########
File path: jena-shacl/src/main/java/org/apache/jena/shacl/engine/SparqlConstraints.java
##########
@@ -91,6 +94,27 @@ public static Constraint parseSparqlConstraint(Graph shapesGraph, Node shape, No
             throw new ShaclParseException("SPARQL parse error: "+ex.getMessage()+"\n"+qs);
         }
     }
+    
+    /**
+     * Test for zero or one occurrences of a tripel pattern that is expected to be   
+     * Returns false for zero, true for one. 
+     * Throws an exception on two or more.
+     */
+    private static boolean absentOrOne(Graph g, Node s, Node p, Node o) {
+        ExtendedIterator<Triple> iter = G.find(g, s, p, null);
+        try {
+            if ( ! iter.hasNext() )
+                return false;
+            iter.next();
+            if ( ! iter.hasNext() )
+                return true;
+            long x = Iter.count(G.find(g, s, p, null));
+            throw new ShaclParseException("More then one (" + x + ") of " + String.format("(%s %s %s)", s, p, o));

Review comment:
       Done




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] strangepleasures commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
strangepleasures commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498459202



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */ 
+    public static boolean contains(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o);
+    }
+    
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+    
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, x, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */ 
+    public static boolean hasType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        return contains(graph, x, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph g, Node s, Node p) {
+        return g.contains(s, p, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o) && Iter.count(g.find(s,p,null)) == 1;

Review comment:
       Ah great!




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] afs commented on pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
afs commented on pull request #804:
URL: https://github.com/apache/jena/pull/804#issuecomment-703301530


   Added
   
   - comments for nearly all public functions.
   - `Objects.requiresNonNull`
   - rename variables e.g. `s` -> `subject`
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] afs commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
afs commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498346201



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+

Review comment:
       Good point. You can see that the code is dated!
   (and `isNodeGraph` even if it isn't current used)




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] strangepleasures commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
strangepleasures commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498275590



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+

Review comment:
       How about isNodeTriple?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] afs commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
afs commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r499553555



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,669 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.*;
+import org.apache.jena.riot.out.NodeFmtLib;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+    public static boolean isNodeTriple(Node n)  { return n != null && n.isNodeTriple(); }
+    public static boolean isNodeGraph(Node n)   { return n != null && n.isNodeGraph(); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */
+    public static boolean contains(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return graph.contains(subject, predicate, object);
+    }
+
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node node, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        Objects.requireNonNull(type, "type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, node, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */
+    public static boolean hasType(Graph graph, Node node, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        Objects.requireNonNull(type, "type");
+        return contains(graph, node, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return graph.contains(subject, predicate, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(subject, predicate, object);
+        try {
+            if ( ! iter.hasNext() )
+                return false;
+            iter.next();
+            return !iter.hasNext();
+        } finally { iter.close(); }
+    }
+
+    /**
+     * Get object, given subject and predicate. Returns one (non-deterministically) or null.
+     * See also {@link #getOneSP} and {@link #getZeroOrOneSP}.
+     */
+    public static Node getSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return object(first(find(graph, subject, predicate, Node.ANY)));
+    }
+
+    // --- Graph walking.
+
+    /**
+     * Get object for subject-predicate. Must be exactly one object; exception
+     * {@linkplain RDFDataException} thrown when none or more than one.
+     */
+    public static Node getOneSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return object(findUnique(graph, subject, predicate, Node.ANY));
+    }
+
+    /**
+     * Get object for subject-predicate. Return null for none, object for one, and
+     * exception {@linkplain RDFDataException} if more than one.
+     */
+    public static Node getZeroOrOneSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return object(findZeroOne(graph, subject, predicate, Node.ANY));
+    }
+
+    /**
+     *  Get the subject, given predicate and object. Returns one (non-deterministically) or null.
+     *  See also {@link #getOnePO} and {@link #getZeroOrOnePO}.
+     */
+    public static Node getPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return object(first(find(graph, Node.ANY, predicate, object)));
+    }
+
+    /**
+     * Get the subject for predicate-object. Must be exactly one subject; exception
+     * {@linkplain RDFDataException} thrown when none or more than one.
+     */
+    public static Node getOnePO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return subject(findUnique(graph, Node.ANY, predicate, object));
+    }
+
+    /**
+     * Get the subject for predicate-object. Return null for none, subject for one, throw
+     * exception {@linkplain RDFDataException} if more than one.
+     */
+    public static Node getZeroOrOnePO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return subject(findZeroOne(graph, Node.ANY, predicate, object));
+    }
+
+    /**
+     * Get triple if there is exactly one to match the s/p/o, else throw
+     * {@linkplain RDFDataException}.
+     */
+    public static Triple getOne(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return findUnique(graph, subject, predicate, object);
+    }
+
+    /**
+     * Get triple if there is exactly one to match the s/p/o; return null if none;
+     * throw {@linkplain RDFDataException} if more than one.
+     */
+    public static Triple getZeroOrOne(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return findZeroOne(graph, subject, predicate, object);
+    }
+
+    // ---- Multiple matches.
+
+    /**
+     * {@link ExtendedIterator} of objects where the triple matches for subject and
+     * predicate (which can be wildcards). The {@link ExtendedIterator} must be fully
+     * used or explicitly closed. It is preferable use {@link #listSP} which handles
+     * this condition.
+     */
+    public static ExtendedIterator<Node> iterSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, subject, predicate, null).mapWith(Triple::getObject);
+    }
+
+    /**
+     * List of objects matching the subject-predicate (which can be wildcards).
+     */
+    public static List<Node> listSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return iterSP(graph, subject, predicate).toList();
+    }
+
+    /** Count matches of subject-predicate (which can be wildcards). */
+    public static long countSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return Iter.count(iterSP(graph, subject, predicate));
+    }
+
+    /**
+     * {@link ExtendedIterator} of subjects where the triple matches for predicate
+     * and object (which can be wildcards). The {@link ExtendedIterator} must be
+     * fully used or explicitly closed. It is preferable use {@link #listSP} which
+     * handles this condition.
+     */
+    public static ExtendedIterator<Node> iterPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, null, predicate, object).mapWith(Triple::getSubject);
+    }
+
+    /**
+     * List of subjects matching the predicate-object (which can be wildcards).
+     */
+    public static List<Node> listPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return iterPO(graph, predicate, object).toList();
+    }
+
+    /** Count matches of predicate-object (which can be wildcards). */
+    public static long countPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return Iter.count(iterPO(graph, predicate, object));
+    }
+
+    // DISTINCT means these are space using.
+
+    /** List the subjects in a graph (no duplicates) */
+    public static Iterator<Node> listSubjects(Graph graph) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
+        return Iter.iter(iter).map(Triple::getSubject).distinct();
+    }
+
+    /** List the predicates in a graph (no duplicates) */
+    public static Iterator<Node> listPredicates(Graph graph) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
+        return Iter.iter(iter).map(Triple::getPredicate).distinct();
+    }
+
+    /** List the objects in a graph (no duplicates) */
+    public static Iterator<Node> listObjects(Graph graph) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
+        return Iter.iter(iter).map(Triple::getObject).distinct();
+    }
+
+    // ---- rdf:type, not RDFS
+
+    /**
+     * List the subjects with exactly {@code type}.
+     * See {@link #listNodesOfTypeRDFS(Graph, Node)}, which does include sub-classes.
+     */
+    public static List<Node> nodesOfTypeAsList(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        return find(graph, null, rdfType, type).mapWith(Triple::getSubject).toList();
+    }
+
+    /**
+     * List the types of a node/subject.
+     * See {@link #listTypesOfNodeRDFS(Graph, Node)} , which does include super-classes.
+     */
+    public static List<Node> typesOfNodeAsList(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        return find(graph, node, rdfType, null).mapWith(Triple::getObject).toList();
+    }
+
+    /**
+     * Set of nodes with exactly {@code type}.
+     * See {@link #allNodesOfTypeRDFS(Graph, Node)}, which does include sub-classes.
+     */
+    public static Set<Node> nodesOfTypeAsSet(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        return find(graph, null, rdfType, type).mapWith(Triple::getSubject).toSet();
+    }
+
+    /**
+     * Set of exact types of a node See {@link #allTypesOfNodeRDFS(Graph, Node)},
+     * which does include super-classes.
+     */
+    public static Set<Node> typesOfNodeAsSet(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        return find(graph, node, rdfType, null).mapWith(Triple::getObject).toSet();
+    }
+
+    // ---- RDF list.
+
+    /** Return a java list for an RDF list of data. */
+    public static List<Node> rdfList(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        GNode gNode = GNode.create(graph, node);
+        return GraphList.members(gNode);
+    }
+
+    // Sub-class / super-class
+
+    /**
+     * List the subclasses of a type, including itself.
+     * This is <tt>?x rdfs:subClassOf* type</tt>.
+     * The list does not contain duplicates.
+     */
+    public static List<Node> listSubClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        List<Node> acc = new ArrayList<>();
+        // Subclasses are follow rdfs:subClassOf in reverse - object to subject.
+        // Transitive.transitive is "visit once".
+        Transitive.transitiveInc(graph, false, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    /**
+     * List the super-classes of a type, including itself.
+     * This is <tt>type rdfs:subClassOf* ?x</tt>.
+     * The list does not contain duplicates.
+     */
+    public static List<Node> listSuperClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        List<Node> acc = new ArrayList<>();
+        // Super classes are "follow rdfs:subclassOf" - subject to object.
+        // Transitive.transitive is "visit once".
+        Transitive.transitiveInc(graph, true, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    /**
+     * Set of the subclasses of a type, including itself.
+     * This is <tt>?x rdfs:subClassOf* type</tt>.
+     */
+    public static Set<Node> subClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        Set<Node> acc = new HashSet<>();
+        // Subclasses are follow rdfs:subclassOf in reverse - object to subject.
+        Transitive.transitiveInc(graph, false, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    /**
+     * Set of the subclasses of a type, including itself.
+     * This is <tt>?x rdfs:subClassOf* type</tt>.
+     */
+    public static Set<Node> superClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        Set<Node> acc = new HashSet<>();
+        Transitive.transitiveInc(graph, true, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    // ---- RDFS
+
+    /**
+     * List the types of a node, following rdfs:subClassOf for super classes.
+     */
+    public static List<Node> listTypesOfNodeRDFS(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        List<Node> types = typesOfNodeAsList(graph, node);
+        List<Node> types2 = new ArrayList<>();
+        types.forEach(t->{
+            List<Node> subClasses = listSuperClasses(graph, t);
+            types2.addAll(subClasses);
+        });
+        return types2;
+    }
+
+    /**
+     * List all the nodes of type, including node of sub-classes.
+     */
+    public static List<Node> listNodesOfTypeRDFS(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        List<Node> types = listSubClasses(graph, type);
+        List<Node> nodes = new ArrayList<>();
+        accNodesOfTypes(nodes, graph, types);
+        return nodes;
+    }
+
+    /**
+     * List all the types of a node, including super-classes.
+     */
+    public static Set<Node> allTypesOfNodeRDFS(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        Set<Node> types = typesOfNodeAsSet(graph, node);
+        Set<Node> types2 = new HashSet<>();
+        types.forEach(t->{
+            List<Node> subClasses = listSuperClasses(graph, t);
+            types2.addAll(subClasses);
+        });
+        return types2;
+    }
+
+    /** List all the node of type, including considering rdfs:subClassOf */
+    public static Set<Node> allNodesOfTypeRDFS(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        Set<Node> types = subClasses(graph, type);
+        Set<Node> nodes = new HashSet<>();
+        accNodesOfTypes(nodes, graph, types);
+        return nodes;
+    }
+
+    /** For each type, find nodes of that type and accumulate */
+    private static void accNodesOfTypes(Collection<Node> acc, Graph graph, Collection<Node> types) {
+        types.forEach(t->
+            find(graph, null, rdfType, t).mapWith(Triple::getSubject).forEach(acc::add)
+            );
+    }
+
+    /** Return a set of all objects for subject-predicate */
+    public static Set<Node> allSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, subject, predicate, null).mapWith(Triple::getObject).toSet();
+    }
+
+    /** Return a set of all subjects for predicate-object */
+    public static Set<Node> allPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, null, predicate, object).mapWith(Triple::getSubject).toSet();
+    }
+
+    // --- Graph walking.
+
+    /** Count the number of in-arc to an object */
+    public static long objectConnectiveness(Graph graph, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(object, "object");
+        return Iter.count(find(graph, null, null, object));
+    }
+
+    /** Test whether an object has exactly one in-arc. */
+    public static boolean oneConnected(Graph graph, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(object, "object");
+        ExtendedIterator<Triple> iter = find(graph, null, null, object);
+        if ( ! iter.hasNext() )
+            // Zero.
+            return false;
+        iter.next();
+        if ( iter.hasNext() )
+            // more than one
+            return false;
+        return true;

Review comment:
       Yes. (It is also most the same as findUnique)
   
   Closing unfinished extended iterators is contract even if many (most?) apps don't care or attend to the detail. In fact, plain in-memory, TDB1, TDB2 and TIM don't rely on this. But as a library it ought to get it right!




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] afs merged pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
afs merged pull request #804:
URL: https://github.com/apache/jena/pull/804


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] kinow commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
kinow commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r499317094



##########
File path: jena-shacl/src/main/java/org/apache/jena/shacl/engine/SparqlConstraints.java
##########
@@ -91,6 +94,27 @@ public static Constraint parseSparqlConstraint(Graph shapesGraph, Node shape, No
             throw new ShaclParseException("SPARQL parse error: "+ex.getMessage()+"\n"+qs);
         }
     }
+    
+    /**
+     * Test for zero or one occurrences of a tripel pattern that is expected to be   

Review comment:
       s/tripel/triple

##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,669 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.*;
+import org.apache.jena.riot.out.NodeFmtLib;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+    public static boolean isNodeTriple(Node n)  { return n != null && n.isNodeTriple(); }
+    public static boolean isNodeGraph(Node n)   { return n != null && n.isNodeGraph(); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */
+    public static boolean contains(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return graph.contains(subject, predicate, object);
+    }
+
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node node, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        Objects.requireNonNull(type, "type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, node, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */
+    public static boolean hasType(Graph graph, Node node, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        Objects.requireNonNull(type, "type");
+        return contains(graph, node, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return graph.contains(subject, predicate, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(subject, predicate, object);
+        try {
+            if ( ! iter.hasNext() )
+                return false;
+            iter.next();
+            return !iter.hasNext();
+        } finally { iter.close(); }
+    }
+
+    /**
+     * Get object, given subject and predicate. Returns one (non-deterministically) or null.
+     * See also {@link #getOneSP} and {@link #getZeroOrOneSP}.
+     */
+    public static Node getSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return object(first(find(graph, subject, predicate, Node.ANY)));
+    }
+
+    // --- Graph walking.
+
+    /**
+     * Get object for subject-predicate. Must be exactly one object; exception
+     * {@linkplain RDFDataException} thrown when none or more than one.
+     */
+    public static Node getOneSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return object(findUnique(graph, subject, predicate, Node.ANY));
+    }
+
+    /**
+     * Get object for subject-predicate. Return null for none, object for one, and
+     * exception {@linkplain RDFDataException} if more than one.
+     */
+    public static Node getZeroOrOneSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return object(findZeroOne(graph, subject, predicate, Node.ANY));
+    }
+
+    /**
+     *  Get the subject, given predicate and object. Returns one (non-deterministically) or null.
+     *  See also {@link #getOnePO} and {@link #getZeroOrOnePO}.
+     */
+    public static Node getPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return object(first(find(graph, Node.ANY, predicate, object)));
+    }
+
+    /**
+     * Get the subject for predicate-object. Must be exactly one subject; exception
+     * {@linkplain RDFDataException} thrown when none or more than one.
+     */
+    public static Node getOnePO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return subject(findUnique(graph, Node.ANY, predicate, object));
+    }
+
+    /**
+     * Get the subject for predicate-object. Return null for none, subject for one, throw
+     * exception {@linkplain RDFDataException} if more than one.
+     */
+    public static Node getZeroOrOnePO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return subject(findZeroOne(graph, Node.ANY, predicate, object));
+    }
+
+    /**
+     * Get triple if there is exactly one to match the s/p/o, else throw
+     * {@linkplain RDFDataException}.
+     */
+    public static Triple getOne(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return findUnique(graph, subject, predicate, object);
+    }
+
+    /**
+     * Get triple if there is exactly one to match the s/p/o; return null if none;
+     * throw {@linkplain RDFDataException} if more than one.
+     */
+    public static Triple getZeroOrOne(Graph graph, Node subject, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return findZeroOne(graph, subject, predicate, object);
+    }
+
+    // ---- Multiple matches.
+
+    /**
+     * {@link ExtendedIterator} of objects where the triple matches for subject and
+     * predicate (which can be wildcards). The {@link ExtendedIterator} must be fully
+     * used or explicitly closed. It is preferable use {@link #listSP} which handles
+     * this condition.
+     */
+    public static ExtendedIterator<Node> iterSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, subject, predicate, null).mapWith(Triple::getObject);
+    }
+
+    /**
+     * List of objects matching the subject-predicate (which can be wildcards).
+     */
+    public static List<Node> listSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return iterSP(graph, subject, predicate).toList();
+    }
+
+    /** Count matches of subject-predicate (which can be wildcards). */
+    public static long countSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return Iter.count(iterSP(graph, subject, predicate));
+    }
+
+    /**
+     * {@link ExtendedIterator} of subjects where the triple matches for predicate
+     * and object (which can be wildcards). The {@link ExtendedIterator} must be
+     * fully used or explicitly closed. It is preferable use {@link #listSP} which
+     * handles this condition.
+     */
+    public static ExtendedIterator<Node> iterPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, null, predicate, object).mapWith(Triple::getSubject);
+    }
+
+    /**
+     * List of subjects matching the predicate-object (which can be wildcards).
+     */
+    public static List<Node> listPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return iterPO(graph, predicate, object).toList();
+    }
+
+    /** Count matches of predicate-object (which can be wildcards). */
+    public static long countPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return Iter.count(iterPO(graph, predicate, object));
+    }
+
+    // DISTINCT means these are space using.
+
+    /** List the subjects in a graph (no duplicates) */
+    public static Iterator<Node> listSubjects(Graph graph) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
+        return Iter.iter(iter).map(Triple::getSubject).distinct();
+    }
+
+    /** List the predicates in a graph (no duplicates) */
+    public static Iterator<Node> listPredicates(Graph graph) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
+        return Iter.iter(iter).map(Triple::getPredicate).distinct();
+    }
+
+    /** List the objects in a graph (no duplicates) */
+    public static Iterator<Node> listObjects(Graph graph) {
+        Objects.requireNonNull(graph, "graph");
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
+        return Iter.iter(iter).map(Triple::getObject).distinct();
+    }
+
+    // ---- rdf:type, not RDFS
+
+    /**
+     * List the subjects with exactly {@code type}.
+     * See {@link #listNodesOfTypeRDFS(Graph, Node)}, which does include sub-classes.
+     */
+    public static List<Node> nodesOfTypeAsList(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        return find(graph, null, rdfType, type).mapWith(Triple::getSubject).toList();
+    }
+
+    /**
+     * List the types of a node/subject.
+     * See {@link #listTypesOfNodeRDFS(Graph, Node)} , which does include super-classes.
+     */
+    public static List<Node> typesOfNodeAsList(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        return find(graph, node, rdfType, null).mapWith(Triple::getObject).toList();
+    }
+
+    /**
+     * Set of nodes with exactly {@code type}.
+     * See {@link #allNodesOfTypeRDFS(Graph, Node)}, which does include sub-classes.
+     */
+    public static Set<Node> nodesOfTypeAsSet(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        return find(graph, null, rdfType, type).mapWith(Triple::getSubject).toSet();
+    }
+
+    /**
+     * Set of exact types of a node See {@link #allTypesOfNodeRDFS(Graph, Node)},
+     * which does include super-classes.
+     */
+    public static Set<Node> typesOfNodeAsSet(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        return find(graph, node, rdfType, null).mapWith(Triple::getObject).toSet();
+    }
+
+    // ---- RDF list.
+
+    /** Return a java list for an RDF list of data. */
+    public static List<Node> rdfList(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        GNode gNode = GNode.create(graph, node);
+        return GraphList.members(gNode);
+    }
+
+    // Sub-class / super-class
+
+    /**
+     * List the subclasses of a type, including itself.
+     * This is <tt>?x rdfs:subClassOf* type</tt>.
+     * The list does not contain duplicates.
+     */
+    public static List<Node> listSubClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        List<Node> acc = new ArrayList<>();
+        // Subclasses are follow rdfs:subClassOf in reverse - object to subject.
+        // Transitive.transitive is "visit once".
+        Transitive.transitiveInc(graph, false, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    /**
+     * List the super-classes of a type, including itself.
+     * This is <tt>type rdfs:subClassOf* ?x</tt>.
+     * The list does not contain duplicates.
+     */
+    public static List<Node> listSuperClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        List<Node> acc = new ArrayList<>();
+        // Super classes are "follow rdfs:subclassOf" - subject to object.
+        // Transitive.transitive is "visit once".
+        Transitive.transitiveInc(graph, true, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    /**
+     * Set of the subclasses of a type, including itself.
+     * This is <tt>?x rdfs:subClassOf* type</tt>.
+     */
+    public static Set<Node> subClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        Set<Node> acc = new HashSet<>();
+        // Subclasses are follow rdfs:subclassOf in reverse - object to subject.
+        Transitive.transitiveInc(graph, false, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    /**
+     * Set of the subclasses of a type, including itself.
+     * This is <tt>?x rdfs:subClassOf* type</tt>.
+     */
+    public static Set<Node> superClasses(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        Set<Node> acc = new HashSet<>();
+        Transitive.transitiveInc(graph, true, type, NodeConst.rdfsSubclassOf, acc);
+        return acc;
+    }
+
+    // ---- RDFS
+
+    /**
+     * List the types of a node, following rdfs:subClassOf for super classes.
+     */
+    public static List<Node> listTypesOfNodeRDFS(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        List<Node> types = typesOfNodeAsList(graph, node);
+        List<Node> types2 = new ArrayList<>();
+        types.forEach(t->{
+            List<Node> subClasses = listSuperClasses(graph, t);
+            types2.addAll(subClasses);
+        });
+        return types2;
+    }
+
+    /**
+     * List all the nodes of type, including node of sub-classes.
+     */
+    public static List<Node> listNodesOfTypeRDFS(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        List<Node> types = listSubClasses(graph, type);
+        List<Node> nodes = new ArrayList<>();
+        accNodesOfTypes(nodes, graph, types);
+        return nodes;
+    }
+
+    /**
+     * List all the types of a node, including super-classes.
+     */
+    public static Set<Node> allTypesOfNodeRDFS(Graph graph, Node node) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(node, "node");
+        Set<Node> types = typesOfNodeAsSet(graph, node);
+        Set<Node> types2 = new HashSet<>();
+        types.forEach(t->{
+            List<Node> subClasses = listSuperClasses(graph, t);
+            types2.addAll(subClasses);
+        });
+        return types2;
+    }
+
+    /** List all the node of type, including considering rdfs:subClassOf */
+    public static Set<Node> allNodesOfTypeRDFS(Graph graph, Node type) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(type, "type");
+        Set<Node> types = subClasses(graph, type);
+        Set<Node> nodes = new HashSet<>();
+        accNodesOfTypes(nodes, graph, types);
+        return nodes;
+    }
+
+    /** For each type, find nodes of that type and accumulate */
+    private static void accNodesOfTypes(Collection<Node> acc, Graph graph, Collection<Node> types) {
+        types.forEach(t->
+            find(graph, null, rdfType, t).mapWith(Triple::getSubject).forEach(acc::add)
+            );
+    }
+
+    /** Return a set of all objects for subject-predicate */
+    public static Set<Node> allSP(Graph graph, Node subject, Node predicate) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, subject, predicate, null).mapWith(Triple::getObject).toSet();
+    }
+
+    /** Return a set of all subjects for predicate-object */
+    public static Set<Node> allPO(Graph graph, Node predicate, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        return find(graph, null, predicate, object).mapWith(Triple::getSubject).toSet();
+    }
+
+    // --- Graph walking.
+
+    /** Count the number of in-arc to an object */
+    public static long objectConnectiveness(Graph graph, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(object, "object");
+        return Iter.count(find(graph, null, null, object));
+    }
+
+    /** Test whether an object has exactly one in-arc. */
+    public static boolean oneConnected(Graph graph, Node object) {
+        Objects.requireNonNull(graph, "graph");
+        Objects.requireNonNull(object, "object");
+        ExtendedIterator<Triple> iter = find(graph, null, null, object);
+        if ( ! iter.hasNext() )
+            // Zero.
+            return false;
+        iter.next();
+        if ( iter.hasNext() )
+            // more than one
+            return false;
+        return true;

Review comment:
       Do we have to close `iter`?

##########
File path: jena-shacl/src/main/java/org/apache/jena/shacl/engine/SparqlConstraints.java
##########
@@ -91,6 +94,27 @@ public static Constraint parseSparqlConstraint(Graph shapesGraph, Node shape, No
             throw new ShaclParseException("SPARQL parse error: "+ex.getMessage()+"\n"+qs);
         }
     }
+    
+    /**
+     * Test for zero or one occurrences of a tripel pattern that is expected to be   
+     * Returns false for zero, true for one. 
+     * Throws an exception on two or more.
+     */
+    private static boolean absentOrOne(Graph g, Node s, Node p, Node o) {
+        ExtendedIterator<Triple> iter = G.find(g, s, p, null);
+        try {
+            if ( ! iter.hasNext() )
+                return false;
+            iter.next();
+            if ( ! iter.hasNext() )
+                return true;
+            long x = Iter.count(G.find(g, s, p, null));
+            throw new ShaclParseException("More then one (" + x + ") of " + String.format("(%s %s %s)", s, p, o));

Review comment:
       s/then/than




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] afs commented on pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
afs commented on pull request #804:
URL: https://github.com/apache/jena/pull/804#issuecomment-702173332


   @ajs6f 
   
   > Question: is this how you expect ideas for a new API to be presented?
   
   I don't have preference. This is a bit different as it is, mostly, moved from `jena-shacl`.  This library also "parked" in a not-API place for the moment so it can be morphed.
   
   `Graph` is a bit different because it is the base of all RDF access. I would have expected a new API to build on top of `Graph` in the same way that `Model` does.
   
   Actually changing `Graph` to add a whole bunch of operations and across different style of API does not seem like a good idea.
   
   Specifically for `G`, it really is adding words to more accurately describe what it going on so even where the operations are one liners, I think it clearer to give the pattern a descriptive name. Other operations wrap up a bit of checking so moving visiual clutter out of the caller app. YMMV.
   
   
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] ajs6f commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
ajs6f commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498327157



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */ 
+    public static boolean contains(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o);
+    }
+    
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+    
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, x, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */ 
+    public static boolean hasType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        return contains(graph, x, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph g, Node s, Node p) {
+        return g.contains(s, p, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o) && Iter.count(g.find(s,p,null)) == 1;

Review comment:
       See https://issues.apache.org/jira/browse/JENA-1956...




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] ajs6f commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
ajs6f commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498327157



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */ 
+    public static boolean contains(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o);
+    }
+    
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+    
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, x, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */ 
+    public static boolean hasType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        return contains(graph, x, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph g, Node s, Node p) {
+        return g.contains(s, p, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o) && Iter.count(g.find(s,p,null)) == 1;

Review comment:
       See https://issues.apache.org/jira/browse/JENA-1601...




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] strangepleasures commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
strangepleasures commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498273018



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */ 
+    public static boolean contains(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o);
+    }
+    
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+    
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, x, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */ 
+    public static boolean hasType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        return contains(graph, x, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph g, Node s, Node p) {
+        return g.contains(s, p, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o) && Iter.count(g.find(s,p,null)) == 1;

Review comment:
       Could be more efficient without counting all triples, e.g. 
   ```
   try (ExtendedIterator<Triple> it = g.find(s, p, null) {
     if (!it.hasNext()) {
        return false;
     }
     it.next();
     return !it.hasNext();
   }
   ```




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] afs commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
afs commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498298631



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */ 
+    public static boolean contains(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o);
+    }
+    
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+    
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, x, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */ 
+    public static boolean hasType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        return contains(graph, x, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph g, Node s, Node p) {
+        return g.contains(s, p, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o) && Iter.count(g.find(s,p,null)) == 1;

Review comment:
       Agreed.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org


[GitHub] [jena] strangepleasures commented on a change in pull request #804: JENA-1974: G, a library of functions for working with Graph.

Posted by GitBox <gi...@apache.org>.
strangepleasures commented on a change in pull request #804:
URL: https://github.com/apache/jena/pull/804#discussion_r498311300



##########
File path: jena-arq/src/main/java/org/apache/jena/riot/other/G.java
##########
@@ -0,0 +1,593 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.jena.riot.other;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.riot.out.NodeFmtLib;
+//import org.apache.jena.shacl.lib.GN;
+//import org.apache.jena.shacl.lib.RDFDataException;
+//import org.apache.jena.shacl.lib.Transitive;
+//import org.apache.jena.shacl.sys.C;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/** A library of functions for working with {@link Graph}. */
+public class G {
+    private G() {}
+    private static Node rdfType = NodeConst.nodeRDFType;
+
+    /** Return the subject of a triple, or null if the triple is null. */
+    public static Node subject(Triple triple) {
+        return triple == null ? null : triple.getSubject();
+    }
+
+    /** Return the predicate of a triple, or null if the triple is null. */
+    public static Node predicate(Triple triple) {
+        return triple == null ? null : triple.getPredicate();
+    }
+
+    /** Return the object of a triple, or null if the triple is null. */
+    public static Node object(Triple triple) {
+        return triple == null ? null : triple.getObject();
+    }
+
+    // ---- Node filter tests.
+    public static boolean isURI(Node n)         { return n != null && n.isURI(); }
+    public static boolean isBlank(Node n)       { return n != null && n.isBlank(); }
+    public static boolean isLiteral(Node n)     { return n != null && n.isLiteral(); }
+    public static boolean isResource(Node n)    { return n != null && (n.isURI()||n.isBlank()); }
+
+    /** Convert null to Node.ANY */
+    public static Node nullAsAny(Node x) { return nullAsDft(x, Node.ANY) ; }
+
+    /** Convert null to some default Node */
+    public static Node nullAsDft(Node x, Node dft) { return x==null ? dft : x ; }
+
+    /** Does the graph match the s/p/o pattern? */ 
+    public static boolean contains(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o);
+    }
+    
+    /** Does the graph use the node anywhere as a subject, predicate or object? */
+    public static boolean containsNode(Graph graph, Node node) {
+        return GraphUtil.containsNode(graph, node);
+//        return
+//            contains(graph, node, Node.ANY, Node.ANY) ||
+//            contains(graph, Node.ANY, Node.ANY, node) ||
+//            contains(graph, Node.ANY, node, Node.ANY) ;
+    }
+    
+    /** Test whether the node has the type or is rdfs:subclassOf. */
+    public static boolean isOfType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        List<Node> allClasses = listSubClasses(graph, type);
+        for ( Node c : allClasses ) {
+            if ( hasType(graph, x, c) )
+                return true;
+        }
+        return false;
+    }
+
+    /** Does the node x have the given type (non-RDFS - no rdfs:subclassOf considered)? */ 
+    public static boolean hasType(Graph graph, Node x, Node type) {
+        Objects.requireNonNull(x, "Subject");
+        Objects.requireNonNull(type, "Type");
+        return contains(graph, x, NodeConst.nodeRDFType, type);
+    }
+
+    //---- get/list/iter
+
+    /** Does node {@code s} have property {@code p} in graph {@code g}? */
+    public static boolean hasProperty(Graph g, Node s, Node p) {
+        return g.contains(s, p, null);
+    }
+
+    /** Contains exactly one. */
+    public static boolean containsOne(Graph g, Node s, Node p, Node o) {
+        return g.contains(s, p, o) && Iter.count(g.find(s,p,null)) == 1;

Review comment:
       Actually, try-with-resources wouldn't work here as ClosableIterator doesn't implement AutoCloseable. It would be quite convenient and shouldn't break anything. `public interface ClosableIterator<T> extends Iterator<T>,  AutoCloseable`




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@jena.apache.org
For additional commands, e-mail: pr-help@jena.apache.org