active-fedora 3.2.0.pre1 → 3.2.0.pre2

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.
Files changed (34) hide show
  1. data/Gemfile.lock +1 -1
  2. data/History.txt +3 -1
  3. data/lib/active_fedora.rb +3 -3
  4. data/lib/active_fedora/associations.rb +0 -2
  5. data/lib/active_fedora/associations/association_collection.rb +15 -1
  6. data/lib/active_fedora/associations/belongs_to_association.rb +5 -1
  7. data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +5 -1
  8. data/lib/active_fedora/base.rb +36 -92
  9. data/lib/active_fedora/datastream.rb +1 -2
  10. data/lib/active_fedora/file_management.rb +73 -0
  11. data/lib/active_fedora/metadata_datastream_helper.rb +3 -1
  12. data/lib/active_fedora/model.rb +6 -18
  13. data/lib/active_fedora/relationships.rb +634 -0
  14. data/lib/active_fedora/samples/special_thing.rb +4 -4
  15. data/lib/active_fedora/semantic_node.rb +97 -236
  16. data/lib/active_fedora/version.rb +1 -1
  17. data/spec/integration/base_file_management_spec.rb +1 -0
  18. data/spec/integration/base_spec.rb +114 -68
  19. data/spec/integration/full_featured_model_spec.rb +0 -1
  20. data/spec/integration/mods_article_integration_spec.rb +0 -1
  21. data/spec/integration/nokogiri_datastream_spec.rb +0 -1
  22. data/spec/integration/rels_ext_datastream_spec.rb +10 -7
  23. data/spec/integration/semantic_node_spec.rb +10 -16
  24. data/spec/samples/models/hydrangea_article.rb +1 -2
  25. data/spec/samples/oral_history_sample_model.rb +1 -1
  26. data/spec/unit/base_spec.rb +26 -16
  27. data/spec/unit/metadata_datastream_spec.rb +1 -0
  28. data/spec/unit/qualified_dublin_core_datastream_spec.rb +1 -0
  29. data/spec/unit/relationship_spec.rb +1 -0
  30. data/spec/unit/relationships_spec.rb +846 -0
  31. data/spec/unit/semantic_node_spec.rb +2 -338
  32. metadata +8 -7
  33. data/lib/active_fedora/relationships_helper.rb +0 -881
  34. data/spec/unit/relationships_helper_spec.rb +0 -800
@@ -5,7 +5,7 @@ require 'xmlsimple'
5
5
  @@last_pid = 0
6
6
 
7
7
  class SpecNode2
8
- include ActiveFedora::RelationshipsHelper
8
+ include ActiveFedora::Relationships
9
9
  include ActiveFedora::SemanticNode
10
10
 
11
11
  attr_accessor :pid
@@ -21,18 +21,10 @@ describe ActiveFedora::SemanticNode do
21
21
  def increment_pid
22
22
  @@last_pid += 1
23
23
  end
24
-
25
- before(:all) do
26
- @pid = "test:sample_pid"
27
- @uri = "info:fedora/#{@pid}"
28
- @sample_solr_hits = [{"id"=>"_PID1_", "has_model_s"=>["info:fedora/afmodel:AudioRecord"]},
29
- {"id"=>"_PID2_", "has_model_s"=>["info:fedora/afmodel:AudioRecord"]},
30
- {"id"=>"_PID3_", "has_model_s"=>["info:fedora/afmodel:AudioRecord"]}]
31
- end
32
24
 
33
25
  before(:each) do
34
26
  class SpecNode
35
- include ActiveFedora::RelationshipsHelper
27
+ include ActiveFedora::Relationships
36
28
  include ActiveFedora::SemanticNode
37
29
 
38
30
  attr_accessor :pid
@@ -91,327 +83,6 @@ describe ActiveFedora::SemanticNode do
91
83
  @node.should respond_to(:internal_uri)
92
84
  end
93
85
 
94
- it 'should provide #has_relationship' do
95
- SpecNode.should respond_to(:has_relationship)
96
- SpecNode.should respond_to(:has_relationship)
97
- end
98
-
99
- describe '#has_relationship' do
100
- it "should create finders based on provided relationship name" do
101
- SpecNode.has_relationship("parts", :is_part_of, :inbound => true)
102
- local_node = SpecNode.new
103
- local_node.should respond_to(:parts_ids)
104
- local_node.should respond_to(:parts_query)
105
- # local_node.should respond_to(:parts)
106
- local_node.should_not respond_to(:containers)
107
- SpecNode.has_relationship("containers", :is_member_of)
108
- local_node.should respond_to(:containers_ids)
109
- local_node.should respond_to(:containers_query)
110
- end
111
-
112
- it "should add a subject and predicate to the relationships array" do
113
- SpecNode.has_relationship("parents", :is_part_of)
114
- SpecNode.relationships.should have_key(:self)
115
- SpecNode.relationships[:self].should have_key(:is_part_of)
116
- end
117
-
118
- it "should use :inbound as the subject if :inbound => true" do
119
- SpecNode.has_relationship("parents", :is_part_of, :inbound => true)
120
- SpecNode.relationships.should have_key(:inbound)
121
- SpecNode.relationships[:inbound].should have_key(:is_part_of)
122
- end
123
-
124
- it 'should create inbound relationship finders' do
125
- SpecNode.expects(:create_inbound_relationship_finders)
126
- SpecNode.has_relationship("parts", :is_part_of, :inbound => true)
127
- end
128
-
129
- it 'should create outbound relationship finders' do
130
- SpecNode.expects(:create_outbound_relationship_finders).times(2)
131
- SpecNode.has_relationship("parts", :is_part_of, :inbound => false)
132
- SpecNode.has_relationship("container", :is_member_of)
133
- end
134
-
135
- it "should create outbound relationship finders that return an array of fedora PIDs" do
136
- SpecNode.has_relationship("containers", :is_member_of, :inbound => false)
137
- local_node = SpecNode.new
138
- local_node.internal_uri = "info:fedora/#{@pid}"
139
-
140
- local_node.expects(:rels_ext).returns(stub("rels_ext", :dirty= => true, :content=>'')).at_least_once
141
- local_node.add_relationship(:is_member_of, "info:fedora/container:A")
142
- local_node.add_relationship(:is_member_of, "info:fedora/container:B")
143
-
144
- containers_result = local_node.containers_ids
145
- containers_result.should be_instance_of(Array)
146
- containers_result.should include("container:A")
147
- containers_result.should include("container:B")
148
- end
149
-
150
- class MockHasRelationship < SpecNode2
151
- has_relationship "testing", :has_part, :type=>SpecNode2
152
- has_relationship "testing2", :has_member, :type=>SpecNode2
153
- has_relationship "testing_inbound", :has_part, :type=>SpecNode2, :inbound=>true
154
- end
155
-
156
- it 'should create relationship descriptions both inbound and outbound' do
157
- @test_object2 = MockHasRelationship.new
158
- @test_object2.pid = increment_pid
159
- @test_object2.stubs(:testing_inbound).returns({})
160
- @test_object2.expects(:rels_ext).returns(stub("rels_ext", :dirty= => true, :content =>'')).at_least_once
161
- @test_object2.add_relationship(:has_model, ActiveFedora::ContentModel.pid_from_ruby_class(SpecNode2))
162
- @test_object2.should respond_to(:testing_append)
163
- @test_object2.should respond_to(:testing_remove)
164
- @test_object2.should respond_to(:testing2_append)
165
- @test_object2.should respond_to(:testing2_remove)
166
- #make sure append/remove method not created for inbound rel
167
- @test_object2.should_not respond_to(:testing_inbound_append)
168
- @test_object2.should_not respond_to(:testing_inbound_remove)
169
-
170
- @test_object2.relationships_desc.should ==
171
- {:inbound=>{"testing_inbound"=>{:type=>SpecNode2,
172
- :predicate=>:has_part,
173
- :inbound=>true,
174
- :singular=>nil}},
175
- :self=>{"testing"=>{:type=>SpecNode2,
176
- :predicate=>:has_part,
177
- :inbound=>false,
178
- :singular=>nil},
179
- "testing2"=>{:type=>SpecNode2,
180
- :predicate=>:has_member,
181
- :inbound=>false,
182
- :singular=>nil}}}
183
- end
184
- end
185
-
186
- describe '#create_inbound_relationship_finders' do
187
-
188
- it 'should respond to #create_inbound_relationship_finders' do
189
- SpecNode.should respond_to(:create_inbound_relationship_finders)
190
- end
191
-
192
- it "should create finders based on provided relationship name" do
193
- SpecNode.create_inbound_relationship_finders("parts", :is_part_of, :inbound => true)
194
- local_node = SpecNode.new
195
- local_node.should respond_to(:parts_ids)
196
- local_node.should_not respond_to(:containers)
197
- SpecNode.create_inbound_relationship_finders("containers", :is_member_of, :inbound => true)
198
- local_node.should respond_to(:containers_ids)
199
- local_node.should respond_to(:containers)
200
- local_node.should respond_to(:containers_from_solr)
201
- local_node.should respond_to(:containers_query)
202
- end
203
-
204
- it "resulting finder should search against solr and use Model#load_instance to build an array of objects" do
205
- solr_result = (mock("solr result", :is_a? => true, :hits => @sample_solr_hits))
206
- SpecNode.create_inbound_relationship_finders("parts", :is_part_of, :inbound => true)
207
- local_node = SpecNode.new()
208
- local_node.expects(:pid).returns("test:sample_pid")
209
- SpecNode.expects(:relationships_desc).returns({:inbound=>{"parts"=>{:predicate=>:is_part_of}}}).at_least_once()
210
- ActiveFedora::SolrService.instance.conn.expects(:query).with("is_part_of_s:info\\:fedora/test\\:sample_pid", :rows=>25).returns(solr_result)
211
- local_node.parts.map(&:pid).should == ["_PID1_", "_PID2_", "_PID3_"]
212
- end
213
-
214
- it "resulting finder should accept :solr as :response_format value and return the raw Solr Result" do
215
- solr_result = mock("solr result")
216
- SpecNode.create_inbound_relationship_finders("constituents", :is_constituent_of, :inbound => true)
217
- local_node = SpecNode.new
218
- mock_repo = mock("repo")
219
- mock_repo.expects(:find_model).never
220
- local_node.expects(:pid).returns("test:sample_pid")
221
- SpecNode.expects(:relationships_desc).returns({:inbound=>{"constituents"=>{:predicate=>:is_constituent_of}}}).at_least_once()
222
- ActiveFedora::SolrService.instance.conn.expects(:query).with("is_constituent_of_s:info\\:fedora/test\\:sample_pid", :rows=>101).returns(solr_result)
223
- local_node.constituents(:response_format => :solr, :rows=>101).should equal(solr_result)
224
- end
225
-
226
-
227
- it "resulting _ids finder should search against solr and return an array of fedora PIDs" do
228
- SpecNode.create_inbound_relationship_finders("parts", :is_part_of, :inbound => true)
229
- local_node = SpecNode.new
230
- local_node.expects(:pid).returns("test:sample_pid")
231
- SpecNode.expects(:relationships_desc).returns({:inbound=>{"parts"=>{:predicate=>:is_part_of}}}).at_least_once()
232
- ActiveFedora::SolrService.instance.conn.expects(:query).with("is_part_of_s:info\\:fedora/test\\:sample_pid", :rows=>25).returns(mock("solr result", :hits => [Hash["id"=>"pid1"], Hash["id"=>"pid2"]]))
233
- local_node.parts(:response_format => :id_array).should == ["pid1", "pid2"]
234
- end
235
-
236
- it "resulting _ids finder should call the basic finder with :result_format => :id_array" do
237
- SpecNode.create_inbound_relationship_finders("parts", :is_part_of, :inbound => true)
238
- local_node = SpecNode.new
239
- local_node.expects(:parts).with(:response_format => :id_array)
240
- local_node.parts_ids
241
- end
242
-
243
- it "resulting _query finder should call relationship_query" do
244
- SpecNode.create_inbound_relationship_finders("parts", :is_part_of, :inbound => true)
245
- local_node = SpecNode.new
246
- local_node.expects(:relationship_query).with("parts")
247
- local_node.parts_query
248
- end
249
- end
250
-
251
- describe '#create_outbound_relationship_finders' do
252
-
253
- it 'should respond to #create_outbound_relationship_finders' do
254
- SpecNode.should respond_to(:create_outbound_relationship_finders)
255
- end
256
-
257
- it "should create finders based on provided relationship name" do
258
- SpecNode.create_outbound_relationship_finders("parts", :is_part_of)
259
- local_node = SpecNode.new
260
- local_node.should respond_to(:parts_ids)
261
- #local_node.should respond_to(:parts) #.with(:type => "AudioRecord")
262
- local_node.should_not respond_to(:containers)
263
- SpecNode.create_outbound_relationship_finders("containers", :is_member_of)
264
- local_node.should respond_to(:containers_ids)
265
- local_node.should respond_to(:containers)
266
- local_node.should respond_to(:containers_from_solr)
267
- local_node.should respond_to(:containers_query)
268
- end
269
-
270
- describe " resulting finder" do
271
- it "should read from relationships array and use Repository.find_model to build an array of objects" do
272
- SpecNode.create_outbound_relationship_finders("containers", :is_member_of)
273
- local_node = SpecNode.new
274
- local_node.expects(:ids_for_outbound).with(:is_member_of).returns(["my:_PID1_", "my:_PID2_", "my:_PID3_"])
275
- mock_repo = mock("repo")
276
- solr_result = mock("solr result", :is_a? => true)
277
- solr_result.expects(:hits).returns(
278
- [{"id"=> "my:_PID1_", "has_model_s"=>["info:fedora/afmodel:SpecNode"]},
279
- {"id"=> "my:_PID2_", "has_model_s"=>["info:fedora/afmodel:SpecNode"]},
280
- {"id"=> "my:_PID3_", "has_model_s"=>["info:fedora/afmodel:SpecNode"]}])
281
-
282
- ActiveFedora::SolrService.instance.conn.expects(:query).with("id:my\\:_PID1_ OR id:my\\:_PID2_ OR id:my\\:_PID3_").returns(solr_result)
283
- local_node.containers.map(&:pid).should == ["my:_PID1_", "my:_PID2_", "my:_PID3_"]
284
- end
285
-
286
- it "should accept :solr as :response_format value and return the raw Solr Result" do
287
- solr_result = mock("solr result")
288
- SpecNode.create_outbound_relationship_finders("constituents", :is_constituent_of)
289
- local_node = SpecNode.new
290
- mock_repo = mock("repo")
291
- mock_repo.expects(:find_model).never
292
- local_node.expects(:rels_ext).returns(stub('rels-ext', :content=>''))
293
- ActiveFedora::SolrService.instance.conn.expects(:query).returns(solr_result)
294
- local_node.constituents(:response_format => :solr).should equal(solr_result)
295
- end
296
-
297
- it "(:response_format => :id_array) should read from relationships array" do
298
- SpecNode.create_outbound_relationship_finders("containers", :is_member_of)
299
- local_node = SpecNode.new
300
- local_node.expects(:ids_for_outbound).with(:is_member_of).returns([])
301
- local_node.containers_ids
302
- end
303
-
304
- it "(:response_format => :id_array) should return an array of fedora PIDs" do
305
- SpecNode.create_outbound_relationship_finders("containers", :is_member_of)
306
- local_node = SpecNode.new
307
- local_node.expects(:rels_ext).returns(stub("rels_ext", :dirty= => true, :content=>'')).at_least_once
308
- local_node.add_relationship(:is_member_of, "demo:10")
309
- result = local_node.containers_ids
310
- result.should be_instance_of(Array)
311
- result.should include("demo:10")
312
- end
313
-
314
- end
315
-
316
- describe " resulting _ids finder" do
317
- it "should call the basic finder with :result_format => :id_array" do
318
- SpecNode.create_outbound_relationship_finders("parts", :is_part_of)
319
- local_node = SpecNode.new
320
- local_node.expects(:parts).with(:response_format => :id_array)
321
- local_node.parts_ids
322
- end
323
- end
324
-
325
- it "resulting _query finder should call relationship_query" do
326
- SpecNode.create_outbound_relationship_finders("containers", :is_member_of)
327
- local_node = SpecNode.new
328
- local_node.expects(:relationship_query).with("containers")
329
- local_node.containers_query
330
- end
331
- end
332
-
333
- describe ".create_bidirectional_relationship_finder" do
334
- before(:each) do
335
- SpecNode.create_bidirectional_relationship_finders("all_parts", :has_part, :is_part_of)
336
- @local_node = SpecNode.new
337
- @local_node.pid = @pid
338
- @local_node.internal_uri = @uri
339
- end
340
- it "should create inbound & outbound finders" do
341
- @local_node.should respond_to(:all_parts_inbound)
342
- @local_node.should respond_to(:all_parts_outbound)
343
- end
344
- it "should rely on inbound & outbound finders" do
345
- @local_node.expects(:all_parts_inbound).with(:rows => 25).returns(["foo1"])
346
- @local_node.expects(:all_parts_outbound).with(:rows => 25).returns(["foo2"])
347
- @local_node.all_parts.should == ["foo1", "foo2"]
348
- end
349
- it "(:response_format => :id_array) should rely on inbound & outbound finders" do
350
- @local_node.expects(:all_parts_inbound).with(:response_format=>:id_array, :rows => 34).returns(["fooA"])
351
- @local_node.expects(:all_parts_outbound).with(:response_format=>:id_array, :rows => 34).returns(["fooB"])
352
- @local_node.all_parts(:response_format=>:id_array, :rows => 34).should == ["fooA", "fooB"]
353
- end
354
- it "(:response_format => :solr) should construct a solr query that combines inbound and outbound searches" do
355
- # get the id array for outbound relationships then construct solr query by combining id array with inbound relationship search
356
- @local_node.expects(:ids_for_outbound).with(:has_part).returns(["mypid:1"])
357
- id_array_query = ActiveFedora::SolrService.construct_query_for_pids(["mypid:1"])
358
- solr_result = mock("solr result")
359
- ActiveFedora::SolrService.instance.conn.expects(:query).with("#{id_array_query} OR (is_part_of_s:info\\:fedora/test\\:sample_pid)", :rows=>25).returns(solr_result)
360
- @local_node.all_parts(:response_format=>:solr)
361
- end
362
-
363
- it "should register both inbound and outbound predicate components" do
364
- @local_node.class.relationships[:inbound].has_key?(:is_part_of).should == true
365
- @local_node.class.relationships[:self].has_key?(:has_part).should == true
366
- end
367
-
368
- it "should register relationship names for inbound, outbound" do
369
- @local_node.relationship_names.include?("all_parts_inbound").should == true
370
- @local_node.relationship_names.include?("all_parts_outbound").should == true
371
- end
372
-
373
- it "should register finder methods for the bidirectional relationship name" do
374
- @local_node.should respond_to(:all_parts)
375
- @local_node.should respond_to(:all_parts_ids)
376
- @local_node.should respond_to(:all_parts_query)
377
- @local_node.should respond_to(:all_parts_from_solr)
378
- end
379
-
380
- it "resulting _query finder should call relationship_query" do
381
- SpecNode.create_bidirectional_relationship_finders("containers", :is_member_of, :has_member)
382
- local_node = SpecNode.new
383
- local_node.expects(:relationship_query).with("containers")
384
- local_node.containers_query
385
- end
386
- end
387
-
388
- describe "#has_bidirectional_relationship" do
389
- it "should ..." do
390
- SpecNode.expects(:create_bidirectional_relationship_finders).with("all_parts", :has_part, :is_part_of, {})
391
- SpecNode.has_bidirectional_relationship("all_parts", :has_part, :is_part_of)
392
- end
393
-
394
- it "should have relationships_by_name and relationships hashes contain bidirectionally related objects" do
395
- SpecNode.has_bidirectional_relationship("all_parts", :has_part, :is_part_of)
396
- @local_node = SpecNode.new
397
- @local_node.pid = "mypid1"
398
- @local_node2 = SpecNode.new
399
- @local_node2.pid = "mypid2"
400
- model_def = ActiveFedora::ContentModel.pid_from_ruby_class(SpecNode)
401
- @local_node.expects(:rels_ext).returns(stub("rels_ext", :dirty= => true, :content=>'')).at_least_once
402
- @local_node.add_relationship(:has_model, model_def)
403
- @local_node2.expects(:rels_ext).returns(stub("rels_ext", :dirty= => true, :content=>'')).at_least_once
404
- @local_node2.add_relationship(:has_model, model_def)
405
- @local_node.add_relationship(:has_part, @local_node2)
406
- @local_node2.add_relationship(:has_part, @local_node)
407
- @local_node.ids_for_outbound(:has_part).should == [@local_node2.pid]
408
- @local_node.ids_for_outbound(:has_model).should == ['afmodel:SpecNode']
409
- @local_node2.ids_for_outbound(:has_part).should == [@local_node.pid]
410
- @local_node2.ids_for_outbound(:has_model).should == ['afmodel:SpecNode']
411
- @local_node.relationships_by_name(false).should == {:self=>{"all_parts_outbound"=>[@local_node2.internal_uri]},:inbound=>{"all_parts_inbound"=>[]}}
412
- @local_node2.relationships_by_name(false).should == {:self=>{"all_parts_outbound"=>[@local_node.internal_uri]},:inbound=>{"all_parts_inbound"=>[]}}
413
- end
414
- end
415
86
 
416
87
  describe ".add_relationship" do
417
88
  it "should add relationship to the relationships graph" do
@@ -444,13 +115,6 @@ describe ActiveFedora::SemanticNode do
444
115
 
445
116
  end
446
117
 
447
- describe '#relationships' do
448
-
449
- it "should return a hash" do
450
- SpecNode.relationships.class.should == Hash
451
- end
452
-
453
- end
454
118
 
455
119
  it "should provide .outbound_relationships" do
456
120
  @node.should respond_to(:outbound_relationships)
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active-fedora
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1923832043
4
+ hash: 1923832045
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - pre
11
- - 1
12
- version: 3.2.0.pre1
11
+ - 2
12
+ version: 3.2.0.pre2
13
13
  platform: ruby
14
14
  authors:
15
15
  - Matt Zumwalt
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-12-21 00:00:00 -06:00
21
+ date: 2011-12-29 00:00:00 -06:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -569,6 +569,7 @@ files:
569
569
  - lib/active_fedora/delegating.rb
570
570
  - lib/active_fedora/digital_object.rb
571
571
  - lib/active_fedora/fedora_object.rb
572
+ - lib/active_fedora/file_management.rb
572
573
  - lib/active_fedora/fixture_loader.rb
573
574
  - lib/active_fedora/metadata_datastream.rb
574
575
  - lib/active_fedora/metadata_datastream_helper.rb
@@ -584,7 +585,7 @@ files:
584
585
  - lib/active_fedora/reflection.rb
585
586
  - lib/active_fedora/relationship.rb
586
587
  - lib/active_fedora/relationship_graph.rb
587
- - lib/active_fedora/relationships_helper.rb
588
+ - lib/active_fedora/relationships.rb
588
589
  - lib/active_fedora/rels_ext_datastream.rb
589
590
  - lib/active_fedora/rubydora_connection.rb
590
591
  - lib/active_fedora/samples.rb
@@ -707,7 +708,7 @@ files:
707
708
  - spec/unit/rdf_xml_writer.rb
708
709
  - spec/unit/relationship_graph_spec.rb
709
710
  - spec/unit/relationship_spec.rb
710
- - spec/unit/relationships_helper_spec.rb
711
+ - spec/unit/relationships_spec.rb
711
712
  - spec/unit/rels_ext_datastream_spec.rb
712
713
  - spec/unit/rubydora_connection_spec.rb
713
714
  - spec/unit/semantic_node_spec.rb
@@ -850,7 +851,7 @@ test_files:
850
851
  - spec/unit/rdf_xml_writer.rb
851
852
  - spec/unit/relationship_graph_spec.rb
852
853
  - spec/unit/relationship_spec.rb
853
- - spec/unit/relationships_helper_spec.rb
854
+ - spec/unit/relationships_spec.rb
854
855
  - spec/unit/rels_ext_datastream_spec.rb
855
856
  - spec/unit/rubydora_connection_spec.rb
856
857
  - spec/unit/semantic_node_spec.rb
@@ -1,881 +0,0 @@
1
- module ActiveFedora
2
- # This module is meant to extend semantic node to add functionality based on a relationship's name
3
- # It is meant to turn a relationship into just another attribute in a model.
4
- # The notion of a "relationship name" is used _internally_ to distinguish between the relationships you've set up using has_relationship and the implicit relationships that are based on the predicates themselves.
5
- #
6
- # @example ActiveFedora
7
- # has_relationship "parents", :is_member_of
8
- #
9
- # obj.parents is a relationship in ActiveFedora while :is_member_of is the literal RDF relationship in Fedora
10
- #
11
- # There are also several helper methods created for any relationship declared in ActiveFedora. For the above example
12
- # the following methods are created:
13
- #
14
- # obj.parents_append(object) Appends an object to the "parents" relationship
15
- # obj.parents_remove(object) Removes an object from the "parents" relationship
16
- # obj.parents_query Returns the query used against solr to retrieve objects linked via the "parents" relationship
17
- #
18
- # Note: ActiveFedora relationships can reflect filters ...
19
- # If you define the solr_fq parameter in your has_relationship call some objects will be filtered out:
20
- #
21
- # has_relationship "parents", :is_member_of, :solr_fq=>"eyes:blue"
22
- #
23
- # Then obj.parents will only return parents where their eyes are blue.
24
- module RelationshipsHelper
25
- extend ActiveSupport::Concern
26
-
27
- included do
28
- class_attribute :class_relationships_desc
29
- end
30
-
31
-
32
- # ** EXPERIMENTAL **
33
- #
34
- # Return array of objects for a given relationship name
35
- # @param [String] Name of relationship to find
36
- # @return [Array] Returns array of objects linked via the relationship name given
37
- def find_relationship_by_name(name)
38
- rels = nil
39
- if inbound_relationship_names.include?(name)
40
- rels = relationships_by_name(false)[:inbound][name]
41
- elsif outbound_relationship_names.include?(name)
42
- rels = relationships_by_name[:self][name]
43
- end
44
- rels = [] if rels.nil?
45
- return rels
46
- end
47
-
48
- # ** EXPERIMENTAL **
49
- #
50
- # Internal method that ensures a relationship subject such as :self and :inbound
51
- # exist within the relationships_desc hash tracking relationships metadata.
52
- # This method just calls the class method counterpart of this method.
53
- # @param [Symbol] Subject name to register (will probably be something like :self or :inbound)
54
- def register_relationship_desc_subject(subject)
55
- self.class.register_relationship_desc_subject(subject)
56
- end
57
-
58
- # ** EXPERIMENTAL **
59
- #
60
- # Internal method that adds a relationship description for a
61
- # relationship name and predicate pair to either an outbound (:self)
62
- # or inbound (:inbound) relationship types. This method just calls the class method counterpart of this method.
63
- # @param [Symbol] Subject name to register
64
- # @param [String] Name of relationship being registered
65
- # @param [Symbol] Fedora ontology predicate to use
66
- # @param [Hash] Any options passed to has_relationship such as :type, :solr_fq, etc.
67
- def register_relationship_desc(subject, name, predicate, opts={})
68
- self.class.register_relationship_desc(subject, name, predicate, opts)
69
- end
70
-
71
- # ** EXPERIMENTAL **
72
- #
73
- # Gets the relationships hash with subject mapped to relationship
74
- # names instead of relationship predicates (unlike the "relationships" method in SemanticNode)
75
- # It has an optional parameter of outbound_only that defaults true.
76
- # If false it will include inbound relationships in the results.
77
- # Also, it will only reload outbound relationships if the relationships hash has changed
78
- # since the last time this method was called.
79
- # @param [Boolean] if false it will include inbound relationships (defaults to true)
80
- # @return [Hash] Returns a hash of subject name (:self or :inbound) mapped to nested hashs of each relationship name mapped to an Array of objects linked via the relationship
81
- def relationships_by_name(outbound_only=true)
82
- @relationships_by_name = relationships_by_name_from_class()
83
- outbound_only ? @relationships_by_name : @relationships_by_name.merge(:inbound=>inbound_relationships_by_name)
84
- end
85
-
86
- # ** EXPERIMENTAL **
87
- #
88
- # Gets relationships by name from the class using the current relationships hash
89
- # and relationship name,predicate pairs.
90
- # @return [Hash] returns the outbound relationships with :self mapped to nested hashs of each relationship name mapped to an Array of objects linked via the relationship
91
- def relationships_by_name_from_class()
92
- rels = {}
93
- relationship_predicates.each_pair do |subj, names|
94
- case subj
95
- when :self
96
- rels[:self] = {}
97
- names.each_pair do |name, predicate|
98
- set = []
99
- res = relationships.query(:predicate => Predicates.find_graph_predicate(predicate))
100
- res.each_object do |o|
101
- set << o.to_s
102
- end
103
- rels[:self][name] = set
104
- end
105
- when :inbound
106
- #nop
107
- # inbound = inbound_relationships
108
- # names.each_pair do |name, predicate|
109
- # rels[:inbound][name] = inbound[predicate]
110
- # end
111
- end
112
- end
113
- return rels
114
- end
115
-
116
-
117
- # ** EXPERIMENTAL **
118
- #
119
- # Return hash of relationships_by_name defined within other objects' RELS-EXT
120
- # It returns a hash of relationship name to arrays of objects. It requeries
121
- # solr each time this method is called.
122
- # @return [Hash] Return hash of each relationship name mapped to an Array of objects linked to this object via inbound relationships
123
- def inbound_relationships_by_name
124
- rels = {}
125
- if relationships_desc.has_key?(:inbound)&&!relationships_desc[:inbound].empty?()
126
- inbound_rels = inbound_relationships
127
-
128
- if relationship_predicates.has_key?(:inbound)
129
- relationship_predicates[:inbound].each do |name, predicate|
130
- rels[name] = inbound_rels.has_key?(predicate) ? inbound_rels[predicate] : []
131
- end
132
- end
133
- end
134
- return rels
135
- end
136
-
137
- # ** EXPERIMENTAL **
138
- #
139
- # Return hash of outbound relationship names and predicate pairs
140
- # @return [Hash] A hash of outbound relationship names mapped to predicates used
141
- def outbound_relationship_predicates
142
- relationship_predicates.has_key?(:self) ? relationship_predicates[:self] : {}
143
- end
144
-
145
- # ** EXPERIMENTAL **
146
- #
147
- # Return hash of inbound relationship names and predicate pairs
148
- # @return [Hash] A hash of inbound relationship names mapped to predicates used
149
- def inbound_relationship_predicates
150
- relationship_predicates.has_key?(:inbound) ? relationship_predicates[:inbound] : {}
151
- end
152
-
153
- # ** EXPERIMENTAL **
154
- #
155
- # Return hash of relationship names and predicate pairs (inbound and outbound).
156
- # This method calls the class method version of this method to get the static settings
157
- # defined in the class definition.
158
- # @return [Hash] A hash of relationship names (inbound and outbound) mapped to predicates used
159
- def relationship_predicates
160
- @relationship_predicates ||= relationship_predicates_from_class
161
- end
162
-
163
- # ** EXPERIMENTAL **
164
- #
165
- # Return hash of relationship names and predicate pairs from class.
166
- # It retrieves this information via the relationships_desc hash in the class.
167
- # @return [Hash] A hash of relationship names (inbound and outbound) mapped to predicates used
168
- def relationship_predicates_from_class
169
- rels = {}
170
- relationships_desc.each_pair do |subj, names|
171
- rels[subj] = {}
172
- names.each_pair do |name, args|
173
- rels[subj][name] = args[:predicate]
174
- end
175
- end
176
- return rels
177
- end
178
-
179
- # ** EXPERIMENTAL **
180
- #
181
- # Return array all relationship names
182
- # @return [Array] of relationship names for relationships declared via has_relationship in the class
183
- def relationship_names
184
- names = []
185
- relationships_desc.each_key do |subject|
186
- names = names.concat(relationships_desc[subject].keys)
187
- end
188
- names
189
- end
190
-
191
- # ** EXPERIMENTAL **
192
- #
193
- # Return array of relationship names for all inbound relationships (coming from other objects' RELS-EXT and Solr)
194
- # @return [Array] of inbound relationship names for relationships declared via has_relationship in the class
195
- def inbound_relationship_names
196
- relationships_desc.has_key?(:inbound) ? relationships_desc[:inbound].keys : []
197
- end
198
-
199
- # ** EXPERIMENTAL **
200
- #
201
- # Return array of relationship names for all outbound relationships (coming from this object's RELS-EXT)
202
- # @return [Array] of outbound relationship names for relationships declared via has_relationship in the class
203
- def outbound_relationship_names
204
- relationships_desc.has_key?(:self) ? relationships_desc[:self].keys : []
205
- end
206
-
207
- # ** EXPERIMENTAL **
208
- #
209
- # Return hash of relationships_by_name defined within this object's RELS-EXT
210
- # It returns a hash of relationship name to arrays of objects
211
- # @return [Hash] Return hash of each relationship name mapped to an Array of objects linked to this object via outbound relationships
212
- def outbound_relationships_by_name
213
- relationships_desc.has_key?(:self) ? relationships_by_name[:self] : {}
214
- end
215
-
216
- # ** EXPERIMENTAL **
217
- #
218
- # Returns true if the given relationship name is a relationship
219
- # @param [String] Name of relationship
220
- # @param [Boolean] If false checks inbound relationships as well (defaults to true)
221
- def is_relationship_name?(name, outbound_only=true)
222
- if outbound_only
223
- outbound_relationship_names.include?(name)
224
- else
225
- (outbound_relationship_names.include?(name)||inbound_relationship_names.include?(name))
226
- end
227
- end
228
-
229
- # ** EXPERIMENTAL **
230
- #
231
- # Return hash that persists relationship metadata defined by has_relationship calls
232
- # @return [Hash] Hash of relationship subject (:self or :inbound) mapped to nested hashs of each relationship name mapped to another hash relationship options
233
- # @example For the following relationship
234
- #
235
- # has_relationship "audio_records", :has_part, :type=>AudioRecord
236
- #
237
- # Results in the following returned by relationships_desc
238
- # {:self=>{"audio_records"=>{:type=>AudioRecord, :singular=>nil, :predicate=>:has_part, :inbound=>false}}}
239
- def relationships_desc
240
- @relationships_desc ||= relationships_desc_from_class
241
- end
242
-
243
- # ** EXPERIMENTAL **
244
- #
245
- # Get class instance variable relationships_desc that holds has_relationship metadata
246
- # @return [Hash] Hash of relationship subject (:self or :inbound) mapped to nested hashs of each relationship name mapped to another hash relationship options
247
- def relationships_desc_from_class
248
- self.class.relationships_desc
249
- end
250
-
251
- # ** EXPERIMENTAL **
252
- #
253
- # Return the value of :type for the relationship for name passed in if defined
254
- # It defaults to ActiveFedora::Base.
255
- # @return [Class] the name of the class defined for a relationship by the :type option if present
256
- def relationship_model_type(name)
257
- if is_relationship_name?(name,true)
258
- subject = outbound_relationship_names.include?(name)? :self : :inbound
259
- if relationships_desc[subject][name].has_key?(:type)
260
- return class_from_name(relationships_desc[subject][name][:type])
261
- end
262
- end
263
- return nil
264
- end
265
-
266
- # ** EXPERIMENTAL **
267
- #
268
- # Add an outbound relationship for given relationship name
269
- # See ActiveFedora::SemanticNode::ClassMethods.has_relationship
270
- # @param [String] Name of relationship
271
- # @param [ActiveFedora::Base] object to add to the relationship (expects ActvieFedora::Base to be an ancestor)
272
- # @return [Boolean] returns true if add operation successful
273
- def add_relationship_by_name(name, object)
274
- if is_relationship_name?(name,true)
275
- if relationships_desc[:self][name].has_key?(:type)
276
- klass = class_from_name(relationships_desc[:self][name][:type])
277
- unless klass.nil?
278
- (assert_conforms_to 'object', object, klass)
279
- end
280
- end
281
- add_relationship(outbound_relationship_predicates[name],object)
282
- else
283
- false
284
- end
285
- end
286
-
287
- # ** EXPERIMENTAL **
288
- #
289
- # Remove an object for the given relationship name
290
- # @param [String] Relationship name
291
- # @param [ActiveFedora::Base] object to remove
292
- # @return [Boolean] return true if remove operation successful
293
- def remove_relationship_by_name(name, object)
294
- if is_relationship_name?(name,true)
295
- remove_relationship(outbound_relationship_predicates[name],object)
296
- else
297
- return false
298
- end
299
- end
300
-
301
- # ** EXPERIMENTAL **
302
- #
303
- # Throws an assertion error if conforms_to? returns false for object and model_class
304
- # @param [String] Name of object (just label for output)
305
- # @param [ActiveFedora::Base] Expects to be an object that has ActiveFedora::Base as an ancestor of its class
306
- # @param [Class] The model class used in conforms_to? check on object
307
- def assert_conforms_to(name, object, model_class)
308
- raise "Assertion failure: #{name}: #{object.pid} does not have model #{model_class}, it has model #{relationships[:self][:has_model]}" unless object.conforms_to?(model_class)
309
- end
310
-
311
- # ** EXPERIMENTAL **
312
- #
313
- # Checks that this object is matches the model class passed in.
314
- # It requires two steps to pass to return true
315
- # 1. It has a hasModel relationship of the same model
316
- # 2. kind_of? returns true for the model passed in
317
- # This method can most often be used to detect if an object from Fedora that was created
318
- # with a different model was then used to populate this object.
319
- # @param [Class] the model class name to check if an object conforms_to that model
320
- # @return [Boolean] true if this object conforms to the given model name
321
- def conforms_to?(model_class)
322
- if self.kind_of?(model_class)
323
- #check has model and class match
324
- mod = relationships.first(:predicate=>Predicates.find_graph_predicate(:has_model))
325
- if mod
326
- expected = ActiveFedora::ContentModel.pid_from_ruby_class(self.class)
327
- if mod.object.to_s == expected
328
- return true
329
- else
330
- raise "has_model relationship check failed for model #{model_class} raising exception, expected: '#{expected}' actual: '#{mod.object.to_s}'"
331
- end
332
- else
333
- raise "has_model relationship does not exist for model #{model_class} check raising exception"
334
- end
335
- else
336
- raise "kind_of? check failed for model #{model_class}, actual #{self.class} raising exception"
337
- end
338
- return false
339
- end
340
-
341
- # Returns a Class symbol for the given string for the class name
342
- # @param [String] the class name as a string
343
- # @return [Class] the class as a Class object
344
- def class_from_name(name)
345
- klass = name.to_s.split('::').inject(Kernel) {|scope, const_name|
346
- scope.const_get(const_name)}
347
- (!klass.nil? && klass.is_a?(::Class)) ? klass : nil
348
- end
349
-
350
- # Call this method to return the query used against solr to retrieve any
351
- # objects linked via the relationship name given.
352
- #
353
- # Instead of this method you can also use the helper method
354
- # [relationship_name]_query, i.e. method "parts_query" for relationship "parts" to return the same value
355
- # @param [String] The name of the relationship defined in the model
356
- # @return [String] The query used when querying solr for objects for this relationship
357
- # @example
358
- # Class SampleAFObjRelationshipFilterQuery < ActiveFedora::Base
359
- # #points to all parents linked via is_member_of
360
- # has_relationship "parents", :is_member_of
361
- # #returns only parents that have a level value set to "series"
362
- # has_relationship "series_parents", :is_member_of, :solr_fq=>level_t:series"
363
- # end
364
- # s = SampleAFObjRelationshipFilterQuery.new
365
- # obj = ActiveFedora::Base.new
366
- # s.parents_append(obj)
367
- # s.series_parents_query
368
- # #=> "(id:changeme\\:13020 AND level_t:series)"
369
- # SampleAFObjRelationshipFilterQuery.relationship_query("series_parents")
370
- # #=> "(id:changeme\\:13020 AND level_t:series)"
371
- def relationship_query(relationship_name)
372
- query = ""
373
- if self.class.is_bidirectional_relationship?(relationship_name)
374
- predicate = outbound_relationship_predicates["#{relationship_name}_outbound"]
375
- id_array = ids_for_outbound(predicate)
376
- query = self.class.bidirectional_relationship_query(pid,relationship_name,id_array)
377
- elsif outbound_relationship_names.include?(relationship_name)
378
- predicate = outbound_relationship_predicates[relationship_name]
379
- id_array = ids_for_outbound(predicate)
380
- query = self.class.outbound_relationship_query(relationship_name,id_array)
381
- elsif inbound_relationship_names.include?(relationship_name)
382
- query = self.class.inbound_relationship_query(pid,relationship_name)
383
- end
384
- query
385
- end
386
-
387
- ## Deprecated method checks for HYDRA-541 methods renamed
388
- #
389
- # Old Name New Name
390
- # named_relationship find_relationship_by_name
391
- # register_named_subject register_relationship_desc_subject
392
- # register_named_relationship register_relationship_desc
393
- # named_relationships relationships_by_name
394
- # named_relationships_from_class relationships_by_name_from_class
395
- # named_inbound_relationships inbound_relationship_names
396
- # outbound_named_relationship_predicates outbound_relationship_predicates
397
- # inbound_named_relationship_predicates inbound_relationship_predicates
398
- # named_relationship_predicates relationship_predicates
399
- # named_relationship_predicates_from_class relationship_predicates_from_class
400
- # named_outbound_relationships outbound_relationships_by_name
401
- # is_named_relationship? is_relationship_name?
402
- # named_relationships_desc relationships_desc
403
- # named_relationships_desc_from_class relationships_desc_from_class
404
- # named_relationship_type relationship_model_type
405
- # add_named_relationship add_relationship_by_name
406
- # remove_named_relationship remove_relationship_by_name
407
- # assert_kind_of_model assert_conforms_to
408
- # kind_of_model? conforms_to?
409
- # named_relationship_query relationship_query
410
- # CLASS METHODS
411
- # named_relationships_desc relationships_desc
412
- # register_named_subject register_relationship_desc_subject
413
- # register_named_relationship register_relationship_desc
414
- # create_named_relationship_method create_relationship_name_methods
415
- # create_bidirectional_named_relationship_methods create_bidirectional_relationship_name_methods
416
- # outbound_named_relationship_query outbound_relationship_query
417
- # inbound_named_relationship_query inbound_relationship_query
418
- # bidirectional_named_relationship_query bidirectional_relationship_query
419
- # named_predicate_exists_with_different_name? predicate_exists_with_different_relationship_name?
420
-
421
- # @deprecated Please use {#find_relationship_by_name} instead.
422
- def named_relationship(name)
423
- ActiveSupport::Deprecation.warn("Deprecation: named_relationship has been deprecated. Please call find_relationship_by_name instead.")
424
- find_relationship_by_name(name)
425
- end
426
-
427
- # @deprecated Please use {#register_relationship_desc_subject} instead.
428
- def register_named_subject(subject)
429
- ActiveSupport::Deprecation.warn("Deprecation: register_named_subject has been deprecated. Please call register_relationship_desc_subject instead.")
430
- register_relationship_desc_subject(subject)
431
- end
432
-
433
- # @deprecated Please use {#register_relationship_desc} instead.
434
- def register_named_relationship(subject, name, predicate, opts)
435
- ActiveSupport::Deprecation.warn("Deprecation: register_named_relationship has been deprecated. Please call register_relationship_desc instead.")
436
- register_relationship_desc(subject, name, predicate, opts)
437
- end
438
-
439
- # @deprecated Please use {#relationships_by_name} instead.
440
- def named_relationships(outbound_only=true)
441
- ActiveSupport::Deprecation.warn("Deprecation: named_relationships has been deprecated. Please call relationships_by_name instead.")
442
- relationships_by_name(outbound_only)
443
- end
444
-
445
- # @deprecated Please use {#relationships_by_name_from_class} instead.
446
- def named_relationships_from_class
447
- ActiveSupport::Deprecation.warn("Deprecation: named_relationships_from_class has been deprecated. Please call relationships_by_name_from_class instead.")
448
- relationships_by_name_from_class
449
- end
450
-
451
- # @deprecated Please use {#inbound_relationships_by_name} instead.
452
- def named_inbound_relationships
453
- ActiveSupport::Deprecation.warn("Deprecation: named_inbound_relationships has been deprecated. Please call inbound_relationships_by_name instead.")
454
- inbound_relationships_by_name
455
- end
456
-
457
- # @deprecated Please use {#outbound_relationships_by_name} instead.
458
- def named_outbound_relationships
459
- ActiveSupport::Deprecation.warn("Deprecation: named_outbound_relationships has been deprecated. Please call outbound_relationships_by_name instead.")
460
- outbound_relationships_by_name
461
- end
462
-
463
- # @deprecated Please use {#outbound_relationship_predicates} instead.
464
- def outbound_named_relationship_predicates
465
- ActiveSupport::Deprecation.warn("Deprecation: outbound_named_relationship_predicates has been deprecated. Please call outbound_relationship_predicates instead.")
466
- outbound_relationship_predicates
467
- end
468
-
469
- # @deprecated Please use {#inbound_relationship_predicates} instead.
470
- def inbound_named_relationship_predicates
471
- ActiveSupport::Deprecation.warn("Deprecation: inbound_named_relationship_predicates has been deprecated. Please call inbound_relationship_predicates instead.")
472
- inbound_relationship_predicates
473
- end
474
-
475
- # @deprecated Please use {#relationship_predicates} instead.
476
- def named_relationship_predicates
477
- ActiveSupport::Deprecation.warn("Deprecation: named_relationship_predicates has been deprecated. Please call relationship_predicates instead.")
478
- relationship_predicates
479
- end
480
-
481
- # @deprecated Please use {#relationship_predicates_from_class} instead.
482
- def named_relationship_predicates_from_class
483
- ActiveSupport::Deprecation.warn("Deprecation: named_relationship_predicates_from_class has been deprecated. Please call relationship_predicates_from_class instead.")
484
- relationship_predicates_from_class
485
- end
486
-
487
- # @deprecated Please use {#is_relationship_name?} instead.
488
- def is_named_relationship?(name, outbound_only=true)
489
- ActiveSupport::Deprecation.warn("Deprecation: is_named_relationship? has been deprecated. Please call is_relationship_name? instead.")
490
- is_relationship_name?(name,outbound_only)
491
- end
492
-
493
- # @deprecated Please use {#relationships_desc} instead.
494
- def named_relationships_desc
495
- ActiveSupport::Deprecation.warn("Deprecation: named_relationships_desc has been deprecated. Please call relationships_desc instead.")
496
- relationships_desc
497
- end
498
-
499
- # @deprecated Please use {#relationships_desc_from_class} instead.
500
- def named_relationships_desc_from_class
501
- ActiveSupport::Deprecation.warn("Deprecation: named_relationships_desc_from_class has been deprecated. Please call relationships_desc_from_class instead.")
502
- relationships_desc_from_class
503
- end
504
-
505
- # @deprecated Please use {#relationship_model_type} instead.
506
- def named_relationship_type(name)
507
- ActiveSupport::Deprecation.warn("Deprecation: named_relationship_type has been deprecated. Please call relationship_model_type instead.")
508
- relationship_model_type(name)
509
- end
510
-
511
- # @deprecated Please use {#add_relationship_by_name} instead.
512
- def add_named_relationship(name,object)
513
- ActiveSupport::Deprecation.warn("Deprecation: add_named_relationship has been deprecated. Please call add_relationship_by_name instead.")
514
- add_relationship_by_name(name,object)
515
- end
516
-
517
- # @deprecated Please use {#remove_relationship_by_name} instead.
518
- def remove_named_relationship(name,object)
519
- ActiveSupport::Deprecation.warn("Deprecation: remove_named_relationship has been deprecated. Please call remove_relationship_by_name instead.")
520
- remove_relationship_by_name(name,object)
521
- end
522
-
523
- # @deprecated Please use {#assert_conforms_to} instead.
524
- def assert_kind_of_model(name,object,model_class)
525
- ActiveSupport::Deprecation.warn("Deprecation: assert_kind_of_model has been deprecated. Please call assert_conforms_to instead.")
526
- assert_conforms_to(name,object,model_class)
527
- end
528
-
529
- # @deprecated Please use {#conforms_to?} instead.
530
- def kind_of_model?(model_class)
531
- ActiveSupport::Deprecation.warn("Deprecation: kind_of_model? has been deprecated. Please call conforms_to? instead.")
532
- conforms_to?(model_class)
533
- end
534
-
535
- # @deprecated Please use {#relationship_query} instead.
536
- def named_relationship_query(relationship_name)
537
- ActiveSupport::Deprecation.warn("Deprecation: named_relationship_query has been deprecated. Please call relationship_query instead.")
538
- relationship_query(relationship_name)
539
- end
540
-
541
- module ClassMethods
542
-
543
- # ** EXPERIMENTAL **
544
- #
545
- # Return hash that persists relationship metadata defined by has_relationship calls. If you implement a child class of ActiveFedora::Base it will inherit
546
- # the relationship descriptions defined there by merging in the class
547
- # instance variable values. It will also do this for any level of
548
- # ancestors.
549
- # @return [Hash] Hash of relationship subject (:self or :inbound) mapped to nested hashs of each relationship name mapped to another hash relationship options
550
- # @example
551
- # For the following relationship
552
- #
553
- # has_relationship "audio_records", :has_part, :type=>AudioRecord
554
- #
555
- # Results in the following returned by relationships_desc
556
- # {:self=>{"audio_records"=>{:type=>AudioRecord, :singular=>nil, :predicate=>:has_part, :inbound=>false}}}
557
- def relationships_desc
558
- #get any relationship descriptions from superclasses
559
- if @class_relationships_desc.nil?
560
- @class_relationships_desc ||= Hash[:self => {}]
561
-
562
- #get super classes
563
- super_klasses = []
564
- #insert in reverse order so the child overwrites anything in parent
565
- super_klass = self.superclass
566
- while !super_klass.nil?
567
- super_klasses.insert(0,super_klass)
568
- super_klass = super_klass.superclass
569
- end
570
-
571
- super_klasses.each do |super_klass|
572
- if super_klass.respond_to?(:relationships_desc)
573
- super_rels = super_klass.relationships_desc
574
- super_rels.each_pair do |subject,rels|
575
- @class_relationships_desc[subject] = {} unless @class_relationships_desc.has_key?(subject)
576
- @class_relationships_desc[subject].merge!(rels)
577
- end
578
- end
579
- end
580
- end
581
- @class_relationships_desc
582
- end
583
-
584
- # ** EXPERIMENTAL **
585
- #
586
- # Internal method that ensures a relationship subject such as :self and :inbound
587
- # exist within the relationships_desc hash tracking relationships metadata.
588
- # @param [Symbol] Subject name to register (will probably be something like :self or :inbound)
589
- def register_relationship_desc_subject(subject)
590
- unless relationships_desc.has_key?(subject)
591
- relationships_desc[subject] = {}
592
- end
593
- end
594
-
595
- # ** EXPERIMENTAL **
596
- #
597
- # Internal method that adds relationship name and predicate pair to either an outbound (:self)
598
- # or inbound (:inbound) relationship types. Refer to ActiveFedora::SemanticNode.has_relationship for information on what metadata will be persisted.
599
- # @param [Symbol] Subject name to register
600
- # @param [String] Name of relationship being registered
601
- # @param [Symbol] Fedora ontology predicate to use
602
- # @param [Hash] Any options passed to has_relationship such as :type, :solr_fq, etc.
603
- def register_relationship_desc(subject, name, predicate, opts={})
604
- register_relationship_desc_subject(subject)
605
- opts.merge!({:predicate=>predicate})
606
- relationships_desc[subject][name] = opts
607
- end
608
-
609
- # Tests if the relationship name passed is in bidirectional
610
- # @param [String] relationship name to test
611
- # @return [Boolean]
612
- def is_bidirectional_relationship?(relationship_name)
613
- (relationships_desc.has_key?(:self)&&relationships_desc.has_key?(:inbound)&&relationships_desc[:self].has_key?("#{relationship_name}_outbound") && relationships_desc[:inbound].has_key?("#{relationship_name}_inbound"))
614
- end
615
-
616
- # ** EXPERIMENTAL **
617
- #
618
- # Used in has_relationship call to create dynamic helper methods to
619
- # append and remove objects to and from a relationship
620
- # @param [String] relationship name to create helper methods for
621
- # @example
622
- # For the following relationship
623
- #
624
- # has_relationship "audio_records", :has_part, :type=>AudioRecord
625
- #
626
- # Methods audio_records_append and audio_records_remove are created.
627
- # Boths methods take an object that is kind_of? ActiveFedora::Base as a parameter
628
- def create_relationship_name_methods(name)
629
- append_method_name = "#{name.to_s.downcase}_append"
630
- remove_method_name = "#{name.to_s.downcase}_remove"
631
- self.send(:define_method,:"#{append_method_name}") {|object| add_relationship_by_name(name,object)}
632
- self.send(:define_method,:"#{remove_method_name}") {|object| remove_relationship_by_name(name,object)}
633
- end
634
-
635
- # ** EXPERIMENTAL **
636
- # Similar to +create_relationship_name_methods+ except it is used when an ActiveFedora::Base model class
637
- # declares has_bidirectional_relationship. we are merely creating an alias for outbound portion of bidirectional
638
- # @param [String] bidirectional relationship name
639
- # @param [String] outbound relationship method name associated with the bidirectional relationship ([bidirectional_name]_outbound)
640
- # @example
641
- # has_bidirectional_relationship "members", :has_collection_member, :is_member_of_collection
642
- #
643
- # Method members_outbound_append and members_outbound_remove added
644
- # This method will create members_append which does same thing as members_outbound_append
645
- # and will create members_remove which does same thing as members_outbound_remove
646
- def create_bidirectional_relationship_name_methods(name,outbound_name)
647
- append_method_name = "#{name.to_s.downcase}_append"
648
- remove_method_name = "#{name.to_s.downcase}_remove"
649
- self.send(:define_method,:"#{append_method_name}") {|object| add_relationship_by_name(outbound_name,object)}
650
- self.send(:define_method,:"#{remove_method_name}") {|object| remove_relationship_by_name(outbound_name,object)}
651
- end
652
-
653
- # Returns a solr query for retrieving objects specified in an outbound relationship.
654
- # This method is mostly used by internal method calls.
655
- # It utilizes any solr_fq value defined within a relationship to attach a query filter when
656
- # querying solr on top of just the predicate being used.
657
- # Because it is static it
658
- # needs the pids defined within RELS-EXT for this relationship to be passed in.
659
- # If you are calling this method directly to get the query you should use the
660
- # ActiveFedora::SemanticNode.relationship_query instead or use the helper method
661
- # [relationship_name]_query, i.e. method "parts_query" for relationship "parts". This
662
- # method would only be called directly if you had something like an array of outbound pids
663
- # already in something like a solr document for object that has these relationships.
664
- # @param [String] The name of the relationship defined in the model
665
- # @param [Array] An array of pids to include in the query
666
- # @return [String]
667
- # @example
668
- # Class SampleAFObjRelationshipFilterQuery < ActiveFedora::Base
669
- # #points to all parents linked via is_member_of
670
- # has_relationship "parents", :is_member_of
671
- # #returns only parents that have a level value set to "series"
672
- # has_relationship "series_parents", :is_member_of, :solr_fq=>"level_t:series"
673
- # end
674
- # s = SampleAFObjRelationshipFilterQuery.new
675
- # obj = ActiveFedora::Base.new
676
- # s.series_parents_append(obj)
677
- # s.series_parents_query
678
- # #=> "(id:changeme\\:13020 AND level_t:series)"
679
- # SampleAFObjRelationshipFilterQuery.outbound_relationship_query("series_parents",["id:changeme:13020"])
680
- # #=> "(id:changeme\\:13020 AND level_t:series)"
681
- def outbound_relationship_query(relationship_name,outbound_pids)
682
- query = ActiveFedora::SolrService.construct_query_for_pids(outbound_pids)
683
- subject = :self
684
- if relationships_desc.has_key?(subject) && relationships_desc[subject].has_key?(relationship_name) && relationships_desc[subject][relationship_name].has_key?(:solr_fq)
685
- solr_fq = relationships_desc[subject][relationship_name][:solr_fq]
686
- unless query.empty?
687
- #substitute in the filter query for each pid so that it is applied to each in the query
688
- query_parts = query.split(/OR/)
689
- query = ""
690
- query_parts.each_with_index do |query_part,index|
691
- query_part.strip!
692
- query << " OR " if index > 0
693
- query << "(#{query_part} AND #{solr_fq})"
694
- end
695
- else
696
- query = solr_fq
697
- end
698
- end
699
- query
700
- end
701
-
702
- # Returns a solr query for retrieving objects specified in an inbound relationship.
703
- # This method is mostly used by internal method calls.
704
- # It utilizes any solr_fq value defined within a relationship to attach a query filter
705
- # on top of just the predicate being used. Because it is static it
706
- # needs the pid of the object that has the inbound relationships passed in.
707
- # If you are calling this method directly to get the query you should use the
708
- # ActiveFedora::SemanticNode.relationship_query instead or use the helper method
709
- # [relationship_name]_query, i.e. method "parts_query" for relationship "parts". This
710
- # method would only be called directly if you were working only with Solr and already
711
- # had the pid for the object in something like a solr document.
712
- # @param [String] The pid for the object that has these inbound relationships
713
- # @param [String] The name of the relationship defined in the model
714
- # @return [String]
715
- # @example
716
- # Class SampleAFObjRelationshipFilterQuery < ActiveFedora::Base
717
- # #returns all parts
718
- # has_relationship "parts", :is_part_of, :inbound=>true
719
- # #returns only parts that have level to "series"
720
- # has_relationship "series_parts", :is_part_of, :inbound=>true, :solr_fq=>"level_t:series"
721
- # end
722
- # s = SampleAFObjRelationshipFilterQuery.new
723
- # s.pid
724
- # #=> id:changeme:13020
725
- # s.series_parts_query
726
- # #=> "is_part_of_s:info\\:fedora/changeme\\:13021 AND level_t:series"
727
- # SampleAFObjRelationshipFilterQuery.inbound_relationship_query(s.pid,"series_parts")
728
- # #=> "is_part_of_s:info\\:fedora/changeme\\:13021 AND level_t:series"
729
- def inbound_relationship_query(pid,relationship_name)
730
- query = ""
731
- subject = :inbound
732
- if relationships_desc.has_key?(subject) && relationships_desc[subject].has_key?(relationship_name)
733
- predicate = relationships_desc[subject][relationship_name][:predicate]
734
- internal_uri = "info:fedora/#{pid}"
735
- escaped_uri = internal_uri.gsub(/(:)/, '\\:')
736
- query = "#{predicate}_s:#{escaped_uri}"
737
- if relationships_desc.has_key?(subject) && relationships_desc[subject].has_key?(relationship_name) && relationships_desc[subject][relationship_name].has_key?(:solr_fq)
738
- solr_fq = relationships_desc[subject][relationship_name][:solr_fq]
739
- query << " AND " unless query.empty?
740
- query << solr_fq
741
- end
742
- end
743
- query
744
- end
745
-
746
- # Returns a solr query for retrieving objects specified in a bidirectional relationship.
747
- # This method is mostly used by internal method calls.
748
- # It usea of solr_fq value defined within a relationship to attach a query filter
749
- # on top of just the predicate being used. Because it is static it
750
- # needs the pids defined within RELS-EXT for the outbound relationship as well as the pid of the
751
- # object for the inbound portion of the relationship.
752
- # If you are calling this method directly to get the query you should use the
753
- # ActiveFedora::SemanticNode.relationship_query instead or use the helper method
754
- # [relationship_name]_query, i.e. method "bi_parts_query" for relationship "bi_parts". This
755
- # method would only be called directly if you had something like an array of outbound pids
756
- # already in something like a solr document for object that has these relationships.
757
- # @param [String] The pid for the object that has these inbound relationships
758
- # @param [String] The name of the relationship defined in the model
759
- # @param [Array] An array of pids to include in the query
760
- # @return [String]
761
- # @example
762
- # Class SampleAFObjRelationshipFilterQuery < ActiveFedora::Base
763
- # has_bidirectional_relationship "bi_series_parts", :has_part, :is_part_of, :solr_fq=>"level_t:series"
764
- # end
765
- # s = SampleAFObjRelationshipFilterQuery.new
766
- # obj = ActiveFedora::Base.new
767
- # s.bi_series_parts_append(obj)
768
- # s.pid
769
- # #=> "changeme:13025"
770
- # obj.pid
771
- # #=> id:changeme:13026
772
- # s.bi_series_parts_query
773
- # #=> "(id:changeme\\:13026 AND level_t:series) OR (is_part_of_s:info\\:fedora/changeme\\:13025 AND level_t:series)"
774
- # SampleAFObjRelationshipFilterQuery.bidirectional_relationship_query(s.pid,"series_parents",["id:changeme:13026"])
775
- # #=> "(id:changeme\\:13026 AND level_t:series) OR (is_part_of_s:info\\:fedora/changeme\\:13025 AND level_t:series)"
776
- def bidirectional_relationship_query(pid,relationship_name,outbound_pids)
777
- outbound_query = outbound_relationship_query("#{relationship_name}_outbound",outbound_pids)
778
- inbound_query = inbound_relationship_query(pid,"#{relationship_name}_inbound")
779
- query = outbound_query # use outbound_query by default
780
- if !inbound_query.empty?
781
- query << " OR (" + inbound_relationship_query(pid,"#{relationship_name}_inbound") + ")"
782
- end
783
- return query
784
- end
785
-
786
- # Check if a relationship has any solr query filters defined by has_relationship call
787
- # @param [Symbol] subject to use such as :self or :inbound
788
- # @param [String] relationship name
789
- # @return [Boolean] true if the relationship has a query filter defined
790
- def relationship_has_solr_filter_query?(subject, relationship_name)
791
- relationships_desc.has_key?(subject) && relationships_desc[subject].has_key?(relationship_name) && relationships_desc[subject][relationship_name].has_key?(:solr_fq)
792
- end
793
-
794
- # ** EXPERIMENTAL **
795
- #
796
- # Check to make sure a subject,name, and predicate triple does not already exist
797
- # with the same subject but different name.
798
- # This method is used to ensure conflicting has_relationship calls are not made because
799
- # predicates cannot be reused across relationship names. Otherwise, the mapping of relationship name
800
- # to predicate in RELS-EXT would be broken.
801
- # @param [Symbol] subject to check (:self or :inbound)
802
- # @param [String] relationship name
803
- # @param [Symbol] symbol for Fedora relationship ontology predicate
804
- def predicate_exists_with_different_relationship_name?(subject,name,predicate)
805
- if relationships_desc.has_key?(subject)
806
- relationships_desc[subject].each_pair do |existing_name, args|
807
- return true if !args[:predicate].nil? && args[:predicate] == predicate && existing_name != name
808
- end
809
- end
810
- return false
811
- end
812
-
813
- ## Deprecated class method checks for HYDRA-541 methods renamed
814
- #
815
- # Old Name New Name
816
- # named_relationships_desc relationships_desc
817
- # register_named_subject register_relationship_desc_subject
818
- # register_named_relationship register_relationship_desc
819
- # create_named_relationship_method create_relationship_name_methods
820
- # create_bidirectional_named_relationship_methods create_bidirectional_relationship_name_methods
821
- # outbound_named_relationship_query outbound_relationship_query
822
- # inbound_named_relationship_query inbound_relationship_query
823
- # bidirectional_named_relationship_query bidirectional_relationship_query
824
- # named_predicate_exists_with_different_name? predicate_exists_with_different_relationship_name?
825
-
826
- # @deprecated Please use {#relationships_desc} instead.
827
- def named_relationships_desc
828
- ActiveSupport::Deprecation.warn("Deprecation: named_relationships_desc has been deprecated. Please call relationships_desc instead.")
829
- relationships_desc
830
- end
831
-
832
- # @deprecated Please use {#register_relationship_desc_subject} instead.
833
- def register_named_subject(subject)
834
- ActiveSupport::Deprecation.warn("Deprecation: register_named_subject has been deprecated. Please call register_relationship_desc_subject instead.")
835
- register_relationship_desc_subject(subject)
836
- end
837
-
838
- # @deprecated Please use {#register_relationship_desc} instead.
839
- def register_named_relationship(subject, name, predicate, opts)
840
- ActiveSupport::Deprecation.warn("Deprecation: register_named_relationship has been deprecated. Please call register_relationship_desc instead.")
841
- register_relationship_desc(subject, name, predicate, opts)
842
- end
843
-
844
- # @deprecated Please use {#create_relationship_name_methods} instead.
845
- def create_named_relationship_methods(name)
846
- ActiveSupport::Deprecation.warn("Deprecation: create_named_relationship_methods has been deprecated. Please call create_relationship_name_methods instead.")
847
- create_relationship_name_methods(name)
848
- end
849
-
850
- # @deprecated Please use {#create_bidirectional_relationship_name_methods} instead.
851
- def create_bidirectional_named_relationship_methods(name,outbound_name)
852
- ActiveSupport::Deprecation.warn("Deprecation: create_bidirectional_named_relationship_methods has been deprecated. Please call create_bidirectional_relationship_name_methods instead.")
853
- create_bidirectional_relationship_name_methods(name,outbound_name)
854
- end
855
-
856
- # @deprecated Please use {#outbound_relationship_query} instead.
857
- def outbound_named_relationship_query(relationship_name,outbound_pids)
858
- ActiveSupport::Deprecation.warn("Deprecation: outbound_named_relationship_query has been deprecated. Please call outbound_relationship_query instead.")
859
- outbound_relationship_query(relationship_name,outbound_pids)
860
- end
861
-
862
- # @deprecated Please use {#inbound_relationship_query} instead.
863
- def inbound_named_relationship_query(pid,relationship_name)
864
- ActiveSupport::Deprecation.warn("Deprecation: inbound_named_relationship_query has been deprecated. Please call inbound_relationship_query instead.")
865
- inbound_relationship_query(pid,relationship_name)
866
- end
867
-
868
- # @deprecated Please use {#bidirectional_relationship_query} instead.
869
- def bidirectional_named_relationship_query(pid,relationship_name,outbound_pids)
870
- ActiveSupport::Deprecation.warn("Deprecation: bidirectional_named_relationship_query has been deprecated. Please call bidirectional_relationship_query instead.")
871
- bidirectional_relationship_query(pid,relationship_name,outbound_pids)
872
- end
873
-
874
- # @deprecated Please use {#predicate_exists_with_different_relationship_name?} instead.
875
- def named_predicate_exists_with_different_name?(subject,name,predicate)
876
- ActiveSupport::Deprecation.warn("Deprecation: named_predicate_exists_with_different_name? has been deprecated. Please call predicate_exists_with_different_relationship_name? instead.")
877
- predicate_exists_with_different_relationship_name?(subject,name,predicate)
878
- end
879
- end
880
- end
881
- end