triannon 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +21 -16
- data/Rakefile +15 -18
- data/app/controllers/concerns/rdf_response_formats.rb +16 -14
- data/app/controllers/triannon/annotations_controller.rb +6 -6
- data/app/models/triannon/annotation.rb +5 -5
- data/app/models/triannon/annotation_ldp.rb +17 -16
- data/app/services/triannon/ldp_loader.rb +14 -4
- data/app/services/triannon/ldp_to_oa_mapper.rb +68 -59
- data/app/services/triannon/ldp_writer.rb +180 -59
- data/app/services/triannon/solr_searcher.rb +8 -8
- data/app/services/triannon/solr_writer.rb +12 -12
- data/config/jetty/etc/fedora-override-web.xml +67 -0
- data/config/routes.rb +2 -2
- data/config/triannon.yml +29 -6
- data/lib/generators/triannon/install_generator.rb +23 -3
- data/lib/rdf/triannon_vocab.rb +2 -2
- data/lib/tasks/triannon_tasks.rake +19 -5
- data/lib/triannon.rb +13 -20
- data/lib/triannon/iiif_anno_list.rb +4 -4
- data/lib/triannon/oa_graph_helper.rb +51 -0
- data/lib/triannon/version.rb +1 -1
- metadata +35 -39
- data/app/services/triannon/root_annotation_creator.rb +0 -36
- data/lib/triannon/graph.rb +0 -173
- data/lib/triannon/jsonld_context.rb +0 -13
@@ -4,7 +4,8 @@ module Triannon
|
|
4
4
|
class LdpWriter
|
5
5
|
|
6
6
|
# use LDP protocol to create the OpenAnnotation.Annotation in an RDF store
|
7
|
-
# @param [Triannon::Annotation] anno a Triannon::Annotation object, from
|
7
|
+
# @param [Triannon::Annotation] anno a Triannon::Annotation object, from
|
8
|
+
# which we use the graph
|
8
9
|
def self.create_anno(anno)
|
9
10
|
if anno && anno.graph
|
10
11
|
# TODO: special case if the Annotation object already has an id --
|
@@ -12,13 +13,13 @@ module Triannon
|
|
12
13
|
ldp_writer = Triannon::LdpWriter.new anno
|
13
14
|
id = ldp_writer.create_base
|
14
15
|
|
15
|
-
bodies_solns = anno.graph.query([nil, RDF::
|
16
|
+
bodies_solns = anno.graph.query([nil, RDF::Vocab::OA.hasBody, nil])
|
16
17
|
if bodies_solns.size > 0
|
17
18
|
ldp_writer.create_body_container
|
18
19
|
ldp_writer.create_body_resources
|
19
20
|
end
|
20
21
|
|
21
|
-
targets_solns = anno.graph.query([nil, RDF::
|
22
|
+
targets_solns = anno.graph.query([nil, RDF::Vocab::OA.hasTarget, nil])
|
22
23
|
# NOTE: Annotation is invalid if there are no target statements
|
23
24
|
if targets_solns.size > 0
|
24
25
|
ldp_writer.create_target_container
|
@@ -29,39 +30,130 @@ module Triannon
|
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
|
-
# deletes the indicated container and all its child containers from the LDP
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
33
|
+
# deletes the indicated container and all its child containers from the LDP
|
34
|
+
# store
|
35
|
+
# @param [String] id the unique id for the LDP container for an annotation.
|
36
|
+
# May be a compound id, such as uuid1/t/uuid2, in which case the LDP
|
37
|
+
# container object uuid2 and its children are deleted from the LDP
|
38
|
+
# store, but LDP containers uuid1/t and uuid1 are not deleted from
|
39
|
+
# the LDP store.
|
36
40
|
def self.delete_container id
|
37
41
|
if id && id.size > 0
|
38
42
|
ldpw = Triannon::LdpWriter.new nil
|
39
43
|
ldpw.delete_containers id
|
40
44
|
end
|
41
45
|
end
|
42
|
-
|
43
46
|
class << self
|
44
47
|
alias_method :delete_anno, :delete_container
|
45
48
|
end
|
46
49
|
|
50
|
+
# @param [String] path the path part of the container url, after the ldp base url
|
51
|
+
# @return [Boolean] true if container already exists; false otherwise
|
52
|
+
def self.container_exist? path
|
53
|
+
base_url = Triannon.config[:ldp]['url'].strip
|
54
|
+
path.strip!
|
55
|
+
separator = (base_url.end_with?('/') || path.start_with?('/')) ? "" : '/'
|
56
|
+
conn = Faraday.new url: base_url + separator + path
|
57
|
+
resp = conn.head
|
58
|
+
if resp.status.between?(400, 600)
|
59
|
+
false
|
60
|
+
else
|
61
|
+
true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Creates an empty LDP BasicContainer in LDP Storage
|
66
|
+
# @param [String] parent_path the path part, after the ldp base url -- in
|
67
|
+
# essence, the LDP BasicContainer that will be the parent of the
|
68
|
+
# to-be-created BasicContainer.
|
69
|
+
# @param [String] slug the value to send in Http Header 'Slug' -- this is
|
70
|
+
# appended to the parent container's path to become the id of the newly
|
71
|
+
# created BasicContainer
|
72
|
+
# @return [Boolean] true if the container was created; false otherwise
|
73
|
+
def self.create_basic_container parent_path, slug
|
74
|
+
if slug.blank?
|
75
|
+
puts "create_basic_container called with nil or empty slug, parent_path '#{parent_path}'"
|
76
|
+
return false
|
77
|
+
end
|
78
|
+
base_url = Triannon.config[:ldp]['url'].strip
|
79
|
+
base_url.chop! if base_url.end_with?('/')
|
80
|
+
slug.strip!
|
81
|
+
slug = slug[1..-1] if slug.start_with?('/')
|
82
|
+
if parent_path
|
83
|
+
parent_path.strip!
|
84
|
+
parent_path = parent_path[1..-1] if parent_path.start_with?('/')
|
85
|
+
parent_path.chop! if parent_path.end_with?('/')
|
86
|
+
end
|
87
|
+
|
88
|
+
full_path = (parent_path ? parent_path + '/' : "") + slug
|
89
|
+
full_url = base_url + '/' + full_path
|
90
|
+
|
91
|
+
if container_exist? full_path
|
92
|
+
puts "Container #{full_url} already exists."
|
93
|
+
false
|
94
|
+
else
|
95
|
+
g = RDF::Graph.new
|
96
|
+
null_rel_uri = RDF::URI.new
|
97
|
+
g << [null_rel_uri, RDF.type, RDF::Vocab::LDP.BasicContainer]
|
98
|
+
conn = Faraday.new url: base_url + (parent_path ? '/' + parent_path : "")
|
99
|
+
resp = conn.post do |req|
|
100
|
+
# Note from Fcrepo docs:
|
101
|
+
# https://wiki.duraspace.org/display/FEDORA41/RESTful+HTTP+API+-+Containers#RESTfulHTTPAPI-Containers-BluePOSTCreatenewresourceswithinaLDPcontainer
|
102
|
+
# "If the MIME type corresponds to a supported RDF format or SPARQL-Update, the uploaded content will be
|
103
|
+
# parsed as RDF and used to populate the child node properties. RDF will be interpreted using the current
|
104
|
+
# resource as the base URI (e.g. <> will be expanded to the current URI)."
|
105
|
+
# Thus, the next line is needed even if the body of this POST is empty
|
106
|
+
req.headers['Content-Type'] = 'text/turtle'
|
107
|
+
req.headers['Slug'] = slug
|
108
|
+
req.body = g.to_ttl
|
109
|
+
end
|
110
|
+
|
111
|
+
if resp.status == 201
|
112
|
+
new_url = resp.headers['Location'] ? resp.headers['Location'] : resp.headers['location']
|
113
|
+
if new_url == full_url
|
114
|
+
puts "Created Basic Container #{new_url}"
|
115
|
+
true
|
116
|
+
else
|
117
|
+
puts "Created Basic Container #{new_url} instead of #{full_url}"
|
118
|
+
false
|
119
|
+
end
|
120
|
+
else
|
121
|
+
puts "Unable to create Basic Container #{full_url}: LDP Storage response status #{resp.status}; body #{resp.body}"
|
122
|
+
false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
47
128
|
# @param [Triannon::Annotation] anno a Triannon::Annotation object
|
48
|
-
# @param [String] id the unique id for the LDP container for the passed
|
49
|
-
|
129
|
+
# @param [String] id the unique id for the LDP container for the passed
|
130
|
+
# annotation; defaults to nil
|
131
|
+
def initialize(anno, id = nil)
|
50
132
|
@anno = anno
|
51
133
|
@id = id
|
52
|
-
|
134
|
+
base_url = Triannon.config[:ldp]['url'].strip
|
135
|
+
base_url.chop! if base_url.end_with?('/')
|
136
|
+
container_path = Triannon.config[:ldp]['uber_container']
|
137
|
+
if container_path
|
138
|
+
container_path.strip!
|
139
|
+
container_path = container_path[1..-1] if container_path.start_with?('/')
|
140
|
+
container_path.chop! if container_path.end_with?('/')
|
141
|
+
end
|
142
|
+
@base_uri = "#{base_url}/#{container_path}"
|
53
143
|
end
|
54
144
|
|
55
|
-
# creates a stored LDP container for this object's Annotation, without its
|
145
|
+
# creates a stored LDP container for this object's Annotation, without its
|
146
|
+
# targets or bodies (as those are put in descendant containers)
|
56
147
|
# SIDE EFFECT: assigns the uuid of the container created to @id
|
57
|
-
# @return [String] the unique id for the LDP container created for this
|
148
|
+
# @return [String] the unique id for the LDP container created for this
|
149
|
+
# annotation
|
58
150
|
def create_base
|
59
151
|
if @anno.graph.query([nil, RDF::Triannon.externalReference, nil]).count > 0
|
60
|
-
|
152
|
+
fail Triannon::ExternalReferenceError, "Incoming annotations may not have http://triannon.stanford.edu/ns/externalReference as a predicate."
|
61
153
|
end
|
62
154
|
|
63
155
|
if @anno.graph.id_as_url && @anno.graph.id_as_url.size > 0
|
64
|
-
|
156
|
+
fail Triannon::ExternalReferenceError, "Incoming new annotations may not have an existing id (yet)."
|
65
157
|
end
|
66
158
|
|
67
159
|
# TODO: special case if the Annotation object already has an id --
|
@@ -72,7 +164,7 @@ module Triannon
|
|
72
164
|
@anno.graph.each { |s|
|
73
165
|
g << s
|
74
166
|
}
|
75
|
-
g =
|
167
|
+
g = OA::Graph.new(g)
|
76
168
|
g.remove_non_base_statements
|
77
169
|
g.make_null_relative_uri_out_of_blank_node
|
78
170
|
|
@@ -81,26 +173,27 @@ module Triannon
|
|
81
173
|
|
82
174
|
# creates the LDP container for any and all bodies for this annotation
|
83
175
|
def create_body_container
|
84
|
-
create_direct_container RDF::
|
176
|
+
create_direct_container RDF::Vocab::OA.hasBody
|
85
177
|
end
|
86
178
|
|
87
179
|
# creates the LDP container for any and all targets for this annotation
|
88
180
|
def create_target_container
|
89
|
-
create_direct_container RDF::
|
181
|
+
create_direct_container RDF::Vocab::OA.hasTarget
|
90
182
|
end
|
91
183
|
|
92
184
|
# create the body resources inside the (already created) body container
|
93
185
|
def create_body_resources
|
94
|
-
create_resources_in_container RDF::
|
186
|
+
create_resources_in_container RDF::Vocab::OA.hasBody
|
95
187
|
end
|
96
188
|
|
97
189
|
# create the target resources inside the (already created) target container
|
98
190
|
def create_target_resources
|
99
|
-
create_resources_in_container RDF::
|
191
|
+
create_resources_in_container RDF::Vocab::OA.hasTarget
|
100
192
|
end
|
101
193
|
|
102
|
-
# @param [Array<String>] ldp_container_uris an Array of ids for LDP
|
103
|
-
# e.g. [@base_uri/(uuid1)/t/(uuid2),
|
194
|
+
# @param [Array<String>] ldp_container_uris an Array of ids for LDP
|
195
|
+
# containers. (can also be a String) e.g. [@base_uri/(uuid1)/t/(uuid2),
|
196
|
+
# @base_uri/(uuid1)/t/(uuid3)] or [@base_uri/(uuid)] or (uuid)
|
104
197
|
# @return true if a resource was deleted; false otherwise
|
105
198
|
def delete_containers ldp_container_uris
|
106
199
|
return false if !ldp_container_uris || ldp_container_uris.empty?
|
@@ -112,7 +205,7 @@ module Triannon
|
|
112
205
|
ldp_id = uri.to_s.split(@base_uri + '/').last
|
113
206
|
resp = conn.delete { |req| req.url ldp_id }
|
114
207
|
if resp.status != 204
|
115
|
-
|
208
|
+
fail Triannon::LDPStorageError.new("Unable to delete LDP container #{ldp_id}", resp.status, resp.body)
|
116
209
|
end
|
117
210
|
something_deleted = true
|
118
211
|
}
|
@@ -121,36 +214,57 @@ module Triannon
|
|
121
214
|
|
122
215
|
protected
|
123
216
|
|
124
|
-
# POSTS a ttl representation of a graph to an existing LDP container in the
|
125
|
-
#
|
126
|
-
# @param [String]
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
217
|
+
# POSTS a ttl representation of a graph to an existing LDP container in the
|
218
|
+
# LDP store
|
219
|
+
# @param [String] ttl a turtle representation of RDF data to be put in the
|
220
|
+
# LDP container
|
221
|
+
# @param [String] parent_path the path portion of the url for the LDP parent
|
222
|
+
# container for this resource if no path is supplied, then the resource
|
223
|
+
# will be created as a child of the root annotation; expected paths would
|
224
|
+
# also be (anno_id)/t for a target resource (inside the target container
|
225
|
+
# of anno_id) or (anno_id)/b for a body resource (inside the body
|
226
|
+
# container of anno_id)
|
227
|
+
# @return [String] path_id representing the unique path of the newly created LDP
|
228
|
+
# container
|
131
229
|
def create_resource ttl, parent_path = nil
|
132
230
|
return if !ttl || ttl.empty?
|
231
|
+
|
232
|
+
base_url = @base_uri.strip
|
233
|
+
base_url.chop! if base_url.end_with?('/')
|
234
|
+
if parent_path
|
235
|
+
parent_path.strip!
|
236
|
+
parent_path = parent_path[1..-1] if parent_path.start_with?('/')
|
237
|
+
parent_path.chop! if parent_path.end_with?('/')
|
238
|
+
end
|
239
|
+
|
133
240
|
resp = conn.post do |req|
|
134
241
|
req.url parent_path if parent_path
|
135
242
|
req.headers['Content-Type'] = 'application/x-turtle'
|
136
243
|
req.body = ttl
|
137
244
|
end
|
138
245
|
if resp.status != 200 && resp.status != 201
|
139
|
-
|
246
|
+
fail Triannon::LDPStorageError.new("Unable to create LDP resource in container #{parent_path}; RDF sent: #{ttl}", resp.status, resp.body)
|
140
247
|
end
|
141
248
|
new_url = resp.headers['Location'] ? resp.headers['Location'] : resp.headers['location']
|
142
|
-
|
249
|
+
if new_url
|
250
|
+
new_url = new_url.split(base_url + '/' + parent_path.to_s).last
|
251
|
+
new_url = new_url[1..-1] if new_url.start_with?('/')
|
252
|
+
end
|
253
|
+
new_url
|
143
254
|
end
|
144
255
|
|
145
|
-
# Creates an empty LDP DirectContainer in LDP Storage that is a member of
|
146
|
-
#
|
147
|
-
#
|
256
|
+
# Creates an empty LDP DirectContainer in LDP Storage that is a member of
|
257
|
+
# the base container at @id and has the memberRelation per the
|
258
|
+
# oa_vocab_term. The id of the created container will be (base container
|
259
|
+
# id)/b if hasBody or (base container id)/t if hasTarget
|
260
|
+
# @param [RDF::Vocabulary::Term] oa_vocab_term RDF::Vocab::OA.hasTarget or
|
261
|
+
# RDF::Vocab::OA.hasBody
|
148
262
|
def create_direct_container oa_vocab_term
|
149
263
|
null_rel_uri = RDF::URI.new
|
150
264
|
g = RDF::Graph.new
|
151
|
-
g << [null_rel_uri, RDF.type, RDF::LDP.DirectContainer]
|
152
|
-
g << [null_rel_uri, RDF::LDP.hasMemberRelation, oa_vocab_term]
|
153
|
-
g << [null_rel_uri, RDF::LDP.membershipResource, RDF::URI.new("#{@base_uri}/#{@id}")]
|
265
|
+
g << [null_rel_uri, RDF.type, RDF::Vocab::LDP.DirectContainer]
|
266
|
+
g << [null_rel_uri, RDF::Vocab::LDP.hasMemberRelation, oa_vocab_term]
|
267
|
+
g << [null_rel_uri, RDF::Vocab::LDP.membershipResource, RDF::URI.new("#{@base_uri}/#{@id}")]
|
154
268
|
|
155
269
|
resp = conn.post do |req|
|
156
270
|
req.url "#{@id}"
|
@@ -160,13 +274,15 @@ module Triannon
|
|
160
274
|
req.body = g.to_ttl
|
161
275
|
end
|
162
276
|
if resp.status != 201
|
163
|
-
|
277
|
+
fail Triannon::LDPStorageError.new("Unable to create #{oa_vocab_term.fragment.sub('has', '')} LDP container for anno; RDF sent: #{g.to_ttl}", resp.status, resp.body)
|
164
278
|
end
|
165
279
|
resp
|
166
280
|
end
|
167
281
|
|
168
|
-
# create the target/body resources inside the (already created) target/body
|
169
|
-
#
|
282
|
+
# create the target/body resources inside the (already created) target/body
|
283
|
+
# container
|
284
|
+
# @param [RDF::URI] predicate either RDF::Vocab::OA.hasTarget or
|
285
|
+
# RDF::Vocab::OA.hasBody
|
170
286
|
def create_resources_in_container(predicate)
|
171
287
|
predicate_solns = @anno.graph.query([nil, predicate, nil])
|
172
288
|
resource_ids = []
|
@@ -174,11 +290,13 @@ module Triannon
|
|
174
290
|
graph_for_resource = RDF::Graph.new
|
175
291
|
predicate_obj = predicate_stmt.object
|
176
292
|
if predicate_obj.is_a?(RDF::Node)
|
177
|
-
# we need to use the null relative URI representation of blank nodes
|
293
|
+
# we need to use the null relative URI representation of blank nodes
|
294
|
+
# to write to LDP
|
178
295
|
predicate_subject = RDF::URI.new
|
179
296
|
else
|
180
|
-
# it's already a URI, but we need to use the null relative URI
|
181
|
-
# write out as a Triannon:externalRef
|
297
|
+
# it's already a URI, but we need to use the null relative URI
|
298
|
+
# representation so we can write out as a Triannon:externalRef
|
299
|
+
# property with the URL, and any addl props too.
|
182
300
|
if predicate_obj.to_str
|
183
301
|
predicate_subject = RDF::URI.new
|
184
302
|
graph_for_resource << RDF::Statement({:subject => predicate_subject,
|
@@ -198,19 +316,21 @@ module Triannon
|
|
198
316
|
# add statements with predicate_obj as the subject
|
199
317
|
orig_hash_uri_objs = [] # the orig URI objects from [targetObject, OA.hasSource/.default/.item, (uri)] statements
|
200
318
|
hash_uri_counter = 1
|
201
|
-
|
319
|
+
OA::Graph.subject_statements(predicate_obj, @anno.graph).each { |s|
|
202
320
|
if s.subject == predicate_obj
|
203
321
|
# deal with any external URI references which may occur in:
|
204
|
-
#
|
322
|
+
# OA.hasSource (from SpecificResource), OA.default or
|
323
|
+
# OA.item (from Choice, Composite, List)
|
205
324
|
if s.object.is_a?(RDF::URI) && s.object.to_s
|
206
|
-
# do we need to represent the URL as an externalReference
|
207
|
-
|
325
|
+
# do we need to represent the URL as an externalReference
|
326
|
+
# with hash URI?
|
327
|
+
if s.predicate == RDF::Vocab::OA.hasSource
|
208
328
|
hash_uri_str = "#source"
|
209
|
-
elsif s.predicate == RDF::
|
329
|
+
elsif s.predicate == RDF::Vocab::OA.default
|
210
330
|
hash_uri_str = "#default"
|
211
|
-
elsif s.predicate == RDF::
|
331
|
+
elsif s.predicate == RDF::Vocab::OA.item
|
212
332
|
hash_uri_str = "#item#{hash_uri_counter}"
|
213
|
-
hash_uri_counter
|
333
|
+
hash_uri_counter += 1
|
214
334
|
else
|
215
335
|
# we don't need to represent the object URI as an external ref
|
216
336
|
hash_uri_str = nil
|
@@ -224,7 +344,7 @@ module Triannon
|
|
224
344
|
new_hash_uri_obj = RDF::URI.new(hash_uri_str)
|
225
345
|
orig_hash_uri_obj = s.object
|
226
346
|
orig_hash_uri_objs << orig_hash_uri_obj
|
227
|
-
# add [targetObj, OA.hasSource/.default/.item, (hash URI)]
|
347
|
+
# add [targetObj, OA.hasSource/.default/.item, (hash URI)]
|
228
348
|
graph_for_resource << RDF::Statement({:subject => predicate_subject,
|
229
349
|
:predicate => s.predicate,
|
230
350
|
:object => new_hash_uri_obj})
|
@@ -234,7 +354,7 @@ module Triannon
|
|
234
354
|
:predicate => RDF::Triannon.externalReference,
|
235
355
|
:object => RDF::URI.new(orig_hash_uri_obj.to_s)})
|
236
356
|
# and all of the orig URL's addl props
|
237
|
-
|
357
|
+
OA::Graph.subject_statements(orig_hash_uri_obj, @anno.graph).each { |ss|
|
238
358
|
if ss.subject == orig_hash_uri_obj
|
239
359
|
graph_for_resource << RDF::Statement({:subject => new_hash_uri_obj,
|
240
360
|
:predicate => ss.predicate,
|
@@ -246,7 +366,8 @@ module Triannon
|
|
246
366
|
end
|
247
367
|
# NOTE: already dealt with case where there is no hash uri above
|
248
368
|
else
|
249
|
-
# s.object is not a URI, and subject = predicate_subject -- it may
|
369
|
+
# s.object is not a URI, and subject = predicate_subject -- it may
|
370
|
+
# be a blank node
|
250
371
|
graph_for_resource << RDF::Statement({:subject => predicate_subject,
|
251
372
|
:predicate => s.predicate,
|
252
373
|
:object => s.object})
|
@@ -256,14 +377,14 @@ module Triannon
|
|
256
377
|
graph_for_resource << s
|
257
378
|
end
|
258
379
|
}
|
259
|
-
# make sure the graph we will write contains no extraneous statements
|
260
|
-
#
|
380
|
+
# make sure the graph we will write contains no extraneous statements
|
381
|
+
# about URIs now represented as hash URIs
|
261
382
|
orig_hash_uri_objs.each { |uri_node|
|
262
|
-
|
383
|
+
OA::Graph.subject_statements(uri_node, graph_for_resource).each { |s|
|
263
384
|
graph_for_resource.delete(s)
|
264
385
|
}
|
265
386
|
}
|
266
|
-
if (predicate == RDF::
|
387
|
+
if (predicate == RDF::Vocab::OA.hasTarget)
|
267
388
|
resource_ids << create_resource(graph_for_resource.to_ttl, "#{@id}/t")
|
268
389
|
else
|
269
390
|
resource_ids << create_resource(graph_for_resource.to_ttl, "#{@id}/b")
|
@@ -279,4 +400,4 @@ module Triannon
|
|
279
400
|
end
|
280
401
|
|
281
402
|
end
|
282
|
-
end
|
403
|
+
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
module Triannon
|
2
2
|
class SolrSearcher
|
3
3
|
|
4
|
-
# convert RSolr::Response object into an array of
|
4
|
+
# convert RSolr::Response object into an array of OA::Graph objects,
|
5
5
|
# where each graph object contains a single annotation returned in the response docs
|
6
6
|
# @param [Hash] rsolr_response an RSolr response to a query. It's actually an
|
7
7
|
# RSolr::HashWithResponse but let's not quibble
|
8
|
-
# @return [Array<
|
8
|
+
# @return [Array<OA::Graph>]
|
9
9
|
def self.anno_graphs_array(rsolr_response)
|
10
10
|
result = []
|
11
11
|
# TODO: deal with Solr pagination
|
12
12
|
rsolr_response['response']['docs'].each { |solr_doc_hash|
|
13
|
-
result <<
|
13
|
+
result << OA::Graph.new(RDF::Graph.new.from_jsonld(solr_doc_hash['anno_jsonld']))
|
14
14
|
}
|
15
15
|
result
|
16
16
|
end
|
@@ -129,12 +129,12 @@ module Triannon
|
|
129
129
|
# 2. sends request to Solr
|
130
130
|
# 3. converts Solr response object to array of anno graphs
|
131
131
|
# @param [Hash<String => String>] controller_params params from Controller
|
132
|
-
# @return [Array<
|
132
|
+
# @return [Array<OA::Graph>] array of OA::Graph objects,
|
133
133
|
# where each graph object contains a single annotation returned in the response docs
|
134
134
|
def find(controller_params)
|
135
135
|
solr_params = self.class.solr_params(controller_params)
|
136
136
|
solr_response = search(solr_params)
|
137
|
-
|
137
|
+
self.class.anno_graphs_array(solr_response)
|
138
138
|
end
|
139
139
|
|
140
140
|
|
@@ -149,9 +149,9 @@ module Triannon
|
|
149
149
|
@logger.debug "#{exception.inspect} on Solr search attempt #{attempt_cnt} for #{solr_params.inspect}"
|
150
150
|
if exception.kind_of?(RSolr::Error::Http)
|
151
151
|
# Note there are extra shenanigans b/c RSolr hijacks the Solr error to return RSolr Error
|
152
|
-
|
152
|
+
fail Triannon::SearchError.new("error searching Solr with params #{solr_params.inspect}: #{exception.message}", exception.response[:status], exception.response[:body])
|
153
153
|
elsif exception.kind_of?(StandardError)
|
154
|
-
|
154
|
+
fail Triannon::SearchError.new("error searching Solr with params #{solr_params.inspect}: #{exception.message}")
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
@@ -170,4 +170,4 @@ module Triannon
|
|
170
170
|
end
|
171
171
|
|
172
172
|
end
|
173
|
-
end
|
173
|
+
end
|