|
1 | 1 | (ns com.yetanalytics.flint-jena.triple |
2 | 2 | (:require [com.yetanalytics.flint-jena.ast :as ast]) |
3 | 3 | (:import [org.apache.jena.graph Node Triple] |
| 4 | + [org.apache.jena.sparql.graph NodeConst] |
| 5 | + [org.apache.jena.sparql.lang LabelToNodeMap] |
4 | 6 | [org.apache.jena.sparql.path Path] |
5 | 7 | [org.apache.jena.sparql.core |
6 | 8 | BasicPattern |
|
10 | 12 | [org.apache.jena.sparql.syntax |
11 | 13 | ElementPathBlock |
12 | 14 | ElementTriplesBlock |
13 | | - TripleCollector |
14 | | - TripleCollectorMark])) |
15 | | - |
16 | | -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
17 | | -;; AST Methods |
18 | | -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
19 | | - |
20 | | -;; These multimethod dispatches (specifically `:triple/vec` and `triple/nform`) |
21 | | -;; return ElementPathBlocks since that is the most general syntax Element that |
22 | | -;; can be used in all clauses (WHERE, CONSTRUCT, DELETE, INSERT, etc). |
23 | | - |
24 | | -(defmethod ast/ast-node->jena :triple/path [_ [_ path]] |
25 | | - path) |
26 | | - |
27 | | -(defprotocol Predicate |
28 | | - (-create-triple |
29 | | - [pred subj obj]) |
30 | | - (-add-triple! |
31 | | - [pred subj obj triples] |
32 | | - [pred subj obj triples idx])) |
33 | | - |
34 | | -(extend-protocol Predicate |
35 | | - Node |
36 | | - (-create-triple |
37 | | - [p s o] |
38 | | - (Triple. s p o)) |
39 | | - (-add-triple! |
40 | | - ([p s o ^TripleCollector coll] |
41 | | - (.addTriple coll ^Triple (-create-triple p s o))) |
42 | | - ([p s o ^TripleCollectorMark coll idx] |
43 | | - (.addTriple coll idx ^Triple (-create-triple p s o)))) |
44 | | - |
45 | | - Path |
46 | | - (-create-triple |
47 | | - [p s o] |
48 | | - (TriplePath. s p o)) |
49 | | - (-add-triple! |
50 | | - ([p s o ^TripleCollector coll] |
51 | | - (.addTriplePath coll ^TriplePath (-create-triple p s o))) |
52 | | - ([p s o ^TripleCollectorMark coll idx] |
53 | | - (.addTriplePath coll idx ^TriplePath (-create-triple p s o))))) |
54 | | - |
55 | | -(defmethod ast/ast-node->jena :triple/vec [_ [_ [s p o]]] |
56 | | - (let [triple-block (ElementPathBlock.)] |
57 | | - (-add-triple! p s o triple-block) |
58 | | - triple-block)) |
59 | | - |
60 | | -(defmethod ast/ast-node->jena :triple/nform [_ [_ nform]] |
61 | | - (let [triple-block (ElementPathBlock.)] |
62 | | - (dorun (map-indexed |
63 | | - (fn [idx [s p o]] (-add-triple! p s o triple-block idx)) |
64 | | - nform)) |
65 | | - triple-block)) |
66 | | - |
67 | | -(defmethod ast/ast-node->jena :triple/spo [_ [_ spo]] |
68 | | - (mapcat (fn [[s po-coll]] |
69 | | - (map (fn [[p o]] [s p o]) po-coll)) |
70 | | - spo)) |
71 | | - |
72 | | -(defmethod ast/ast-node->jena :triple/po [_ [_ po]] |
73 | | - (mapcat (fn [[p o-coll]] |
74 | | - (map (fn [o] [p o]) o-coll)) |
75 | | - po)) |
76 | | - |
77 | | -(defmethod ast/ast-node->jena :triple/o [_ [_ o]] |
78 | | - o) |
| 15 | + TripleCollector])) |
79 | 16 |
|
80 | 17 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
81 | 18 | ;; Triple Conversion |
|
146 | 83 | :let [quad (Quad. graph-node triple)]] |
147 | 84 | (.add pattern quad))) |
148 | 85 | pattern)) |
| 86 | + |
| 87 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 88 | +;; Protocols |
| 89 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 90 | + |
| 91 | +(defprotocol SubjectObject |
| 92 | + "Protocol for triple subjects and objects. This covers RDF Lists, |
| 93 | + blank node collections, and regular nodes." |
| 94 | + (-head-node [subject-or-object] |
| 95 | + "Return the Node that external Triples should point to..") |
| 96 | + (-nested-triples [subject-or-object] |
| 97 | + "Return any Triples that are nested in the subject or object.")) |
| 98 | + |
| 99 | +(extend-protocol SubjectObject |
| 100 | + Node |
| 101 | + (-head-node [node] node) |
| 102 | + (-nested-triples [_] [])) |
| 103 | + |
| 104 | +(defrecord RDFList [first-node triples] |
| 105 | + SubjectObject |
| 106 | + (-head-node [_] first-node) |
| 107 | + (-nested-triples [_] (triple-element->seq triples))) |
| 108 | + |
| 109 | +(defrecord BlankNodeColl [subject-node triples] |
| 110 | + SubjectObject |
| 111 | + (-head-node [_] subject-node) |
| 112 | + (-nested-triples [_] (triple-element->seq triples))) |
| 113 | + |
| 114 | +(defprotocol Predicate |
| 115 | + "Protocol for triple predicates. This covers paths and regular nodes." |
| 116 | + (-create-triple [predicate subject object] |
| 117 | + "Create a triple from `subject`, `predicate`, and `object`.")) |
| 118 | + |
| 119 | +(extend-protocol Predicate |
| 120 | + Node |
| 121 | + (-create-triple [pred subj obj] |
| 122 | + (Triple. subj pred obj)) |
| 123 | + |
| 124 | + Path |
| 125 | + (-create-triple [pred subj obj] |
| 126 | + (TriplePath. subj pred obj))) |
| 127 | + |
| 128 | +(defprotocol ASTTriple |
| 129 | + "Protocol for triples (we can't call this \"Triple\" since that would clash |
| 130 | + with Jena's Triple class)." |
| 131 | + (-add-triple! [triple triple-acc] |
| 132 | + "Add `triple` to `triple-acc` (which should be an instance of |
| 133 | + TripleCollector).")) |
| 134 | + |
| 135 | +(extend-protocol ASTTriple |
| 136 | + Triple |
| 137 | + (-add-triple! [triple ^TripleCollector triple-acc] |
| 138 | + (.addTriple triple-acc triple)) |
| 139 | + |
| 140 | + TriplePath |
| 141 | + (-add-triple! [triple-path ^TripleCollector triple-acc] |
| 142 | + (.addTriplePath triple-acc triple-path))) |
| 143 | + |
| 144 | +(defn- create-triple [subj pred obj] |
| 145 | + (-create-triple pred subj obj)) |
| 146 | + |
| 147 | +(defn- add-triple! [triple-acc triple] |
| 148 | + (-add-triple! triple triple-acc)) |
| 149 | + |
| 150 | +(defn- add-triple-coll! [triple-acc triples] |
| 151 | + (dorun (map (fn [triple] (add-triple! triple-acc triple)) |
| 152 | + triples))) |
| 153 | + |
| 154 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 155 | +;; Blank Node + Triple Helpers |
| 156 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 157 | + |
| 158 | +(def rdf-first NodeConst/nodeFirst) |
| 159 | +(def rdf-rest NodeConst/nodeRest) |
| 160 | +(def rdf-nil NodeConst/nodeNil) |
| 161 | + |
| 162 | +(defn- new-bnode! ^Node [^LabelToNodeMap bnode-m] |
| 163 | + (.allocNode bnode-m)) |
| 164 | + |
| 165 | +(defn- s->triples [s] |
| 166 | + (or (not-empty (-nested-triples s)) |
| 167 | + (throw (ex-info "Subject without predicates or objects is not an RDF list or blank node collecton!" |
| 168 | + {:kind ::illegal-subject |
| 169 | + :subject s})))) |
| 170 | + |
| 171 | +(defn- spo->triples [s p o] |
| 172 | + (let [s-node (-head-node s) |
| 173 | + o-node (-head-node o) |
| 174 | + s-triples (-nested-triples s) |
| 175 | + o-triples (-nested-triples o) |
| 176 | + triple (create-triple s-node p o-node)] |
| 177 | + (concat s-triples [triple] o-triples))) |
| 178 | + |
| 179 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 180 | +;; AST Methods |
| 181 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 182 | + |
| 183 | +;; These multimethod dispatches (specifically `:triple.vec/spo` and |
| 184 | +;; `triple.nform/spo`) return ElementPathBlocks since that is the most general |
| 185 | +;; syntax Element that can be used in all clauses (WHERE, CONSTRUCT, DELETE, |
| 186 | +;; INSERT, etc). |
| 187 | + |
| 188 | +(defmethod ast/ast-node->jena :triple/path [_ [_ path]] |
| 189 | + path) |
| 190 | + |
| 191 | +(defn- make-rdf-list [bnode-m list] |
| 192 | + (let [triple-block (ElementPathBlock.) |
| 193 | + init-node (new-bnode! bnode-m)] |
| 194 | + (loop [curr-bnode init-node |
| 195 | + next-bnode (new-bnode! bnode-m) |
| 196 | + list list] |
| 197 | + (if-some [list-entry (first list)] |
| 198 | + (let [node (-head-node list-entry) |
| 199 | + triples (-nested-triples list-entry) |
| 200 | + first-triple (create-triple curr-bnode rdf-first node) |
| 201 | + rest-triple (if (some? (second list)) |
| 202 | + (create-triple curr-bnode rdf-rest next-bnode) |
| 203 | + (create-triple curr-bnode rdf-rest rdf-nil))] |
| 204 | + (add-triple! triple-block first-triple) |
| 205 | + (add-triple-coll! triple-block triples) |
| 206 | + (add-triple! triple-block rest-triple) |
| 207 | + (recur next-bnode (new-bnode! bnode-m) (rest list))) |
| 208 | + (->RDFList init-node triple-block))))) |
| 209 | + |
| 210 | +(defmethod ast/ast-node->jena :triple/list |
| 211 | + [{:keys [active-bnode-map] :as opts} [_ list]] |
| 212 | + (if (empty? list) |
| 213 | + rdf-nil |
| 214 | + (make-rdf-list (get opts @active-bnode-map) list))) |
| 215 | + |
| 216 | +(defn- make-bnode-coll [bnode-m po-pairs] |
| 217 | + (let [triple-block (ElementPathBlock.) |
| 218 | + subj-node (new-bnode! bnode-m)] |
| 219 | + (dorun |
| 220 | + (for [[p o] po-pairs |
| 221 | + :let [o-node (-head-node o) |
| 222 | + o-triples (-nested-triples o) |
| 223 | + triple (create-triple subj-node p o-node)]] |
| 224 | + (do |
| 225 | + (add-triple! triple-block triple) |
| 226 | + (add-triple-coll! triple-block o-triples)))) |
| 227 | + (->BlankNodeColl subj-node triple-block))) |
| 228 | + |
| 229 | +(defmethod ast/ast-node->jena :triple/bnodes |
| 230 | + [{:keys [active-bnode-map] :as opts} [_ po-pairs]] |
| 231 | + (make-bnode-coll (get opts @active-bnode-map) po-pairs)) |
| 232 | + |
| 233 | +;; Vectors |
| 234 | + |
| 235 | +(defmethod ast/ast-node->jena :triple.vec/spo [_ [_ [s p o]]] |
| 236 | + (let [triple-block (ElementPathBlock.) |
| 237 | + triples (spo->triples s p o)] |
| 238 | + (add-triple-coll! triple-block triples) |
| 239 | + triple-block)) |
| 240 | + |
| 241 | +(defmethod ast/ast-node->jena :triple.vec/s [_ [_ [s]]] |
| 242 | + (let [triple-block (ElementPathBlock.) |
| 243 | + triples (s->triples s)] |
| 244 | + (add-triple-coll! triple-block triples) |
| 245 | + triple-block)) |
| 246 | + |
| 247 | +;; Normal Forms |
| 248 | + |
| 249 | +(defmethod ast/ast-node->jena :triple.nform/spo [_ [_ spo]] |
| 250 | + (let [triple-block (ElementPathBlock.) |
| 251 | + triples (mapcat |
| 252 | + (fn [[s po-coll]] |
| 253 | + (if (empty? po-coll) |
| 254 | + (s->triples s) |
| 255 | + (mapcat (fn [[p o]] (spo->triples s p o)) po-coll))) |
| 256 | + spo)] |
| 257 | + (add-triple-coll! triple-block triples) |
| 258 | + triple-block)) |
| 259 | + |
| 260 | +(defmethod ast/ast-node->jena :triple.nform/po [_ [_ po]] |
| 261 | + (mapcat (fn [[p o-coll]] (map (fn [o] [p o]) o-coll)) |
| 262 | + po)) |
| 263 | + |
| 264 | +(defmethod ast/ast-node->jena :triple.nform/po-empty [_ _] |
| 265 | + []) |
| 266 | + |
| 267 | +(defmethod ast/ast-node->jena :triple.nform/o [_ [_ o]] |
| 268 | + o) |
| 269 | + |
| 270 | +;; Quads |
| 271 | + |
| 272 | +(defmethod ast/ast-node->jena :triple.quad/spo |
| 273 | + [_opts [_ triple-elements]] |
| 274 | + (triple-elements->basic-pattern triple-elements)) |
| 275 | + |
| 276 | +(defmethod ast/ast-node->jena :triple.quad/gspo |
| 277 | + [_opts [_ [graph-node triple-bgp]]] |
| 278 | + (basic-pattern->quad-pattern triple-bgp graph-node)) |
0 commit comments