active-fedora 9.10.4 → 9.11.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/History.txt +0 -13
  4. data/lib/active_fedora.rb +7 -0
  5. data/lib/active_fedora/aggregation.rb +11 -0
  6. data/lib/active_fedora/aggregation/base_extension.rb +17 -0
  7. data/lib/active_fedora/aggregation/list_source.rb +103 -0
  8. data/lib/active_fedora/aggregation/ordered_reader.rb +27 -0
  9. data/lib/active_fedora/aggregation/proxy.rb +18 -0
  10. data/lib/active_fedora/associations.rb +40 -0
  11. data/lib/active_fedora/associations/builder/aggregation.rb +51 -0
  12. data/lib/active_fedora/associations/builder/filter.rb +18 -0
  13. data/lib/active_fedora/associations/builder/orders.rb +63 -0
  14. data/lib/active_fedora/associations/filter_association.rb +71 -0
  15. data/lib/active_fedora/associations/orders_association.rb +149 -0
  16. data/lib/active_fedora/attached_files.rb +2 -1
  17. data/lib/active_fedora/attribute_methods.rb +4 -4
  18. data/lib/active_fedora/autosave_association.rb +14 -0
  19. data/lib/active_fedora/base.rb +1 -0
  20. data/lib/active_fedora/cleaner.rb +1 -1
  21. data/lib/active_fedora/errors.rb +3 -0
  22. data/lib/active_fedora/fedora.rb +17 -7
  23. data/lib/active_fedora/file/streaming.rb +13 -4
  24. data/lib/active_fedora/orders.rb +12 -0
  25. data/lib/active_fedora/orders/collection_proxy.rb +8 -0
  26. data/lib/active_fedora/orders/list_node.rb +161 -0
  27. data/lib/active_fedora/orders/ordered_list.rb +264 -0
  28. data/lib/active_fedora/orders/target_proxy.rb +60 -0
  29. data/lib/active_fedora/reflection.rb +215 -42
  30. data/lib/active_fedora/validations.rb +1 -1
  31. data/lib/active_fedora/version.rb +1 -1
  32. data/lib/generators/active_fedora/config/solr/templates/solr/config/schema.xml +1 -1
  33. data/solr/config/schema.xml +1 -1
  34. data/spec/integration/attributes_spec.rb +8 -0
  35. data/spec/integration/file_spec.rb +22 -0
  36. data/spec/integration/has_many_associations_spec.rb +23 -0
  37. data/spec/integration/versionable_spec.rb +6 -6
  38. data/spec/unit/active_fedora_spec.rb +1 -1
  39. data/spec/unit/aggregation/list_source_spec.rb +134 -0
  40. data/spec/unit/aggregation/ordered_reader_spec.rb +43 -0
  41. data/spec/unit/fedora_spec.rb +1 -1
  42. data/spec/unit/filter_spec.rb +133 -0
  43. data/spec/unit/ordered_spec.rb +369 -0
  44. data/spec/unit/orders/list_node_spec.rb +151 -0
  45. data/spec/unit/orders/ordered_list_spec.rb +335 -0
  46. data/spec/unit/orders/reflection_spec.rb +22 -0
  47. data/spec/unit/reflection_spec.rb +2 -4
  48. metadata +25 -3
@@ -0,0 +1,369 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveFedora::Orders do
4
+ subject { Image.new }
5
+ before do
6
+ class Member < ActiveFedora::Base
7
+ end
8
+ class BadClass < ActiveFedora::Base
9
+ end
10
+ class Image < ActiveFedora::Base
11
+ ordered_aggregation :members, through: :list_source
12
+ end
13
+ end
14
+ after do
15
+ Object.send(:remove_const, :Image)
16
+ Object.send(:remove_const, :Member)
17
+ Object.send(:remove_const, :BadClass)
18
+ end
19
+ describe "<<" do
20
+ it "does not accept base objects" do
21
+ member = Member.new
22
+ expect { subject.ordered_member_proxies << member }.to raise_error ActiveFedora::AssociationTypeMismatch
23
+ expect(subject).not_to be_changed
24
+ expect(subject.list_source).not_to be_changed
25
+ end
26
+ end
27
+
28
+ describe "ordered_by" do
29
+ let(:image) { Image.new }
30
+
31
+ context "an element aggregated by one record" do
32
+ it "can find the record that contains it" do
33
+ m = Member.create
34
+ image.ordered_members << m
35
+ image.save
36
+
37
+ expect(m.ordered_by.to_a).to eq [image]
38
+ end
39
+ end
40
+
41
+ context "a new element" do
42
+ it "returns an empty array" do
43
+ m = Member.new
44
+ expect(m.ordered_by.to_a).to eq []
45
+ end
46
+ end
47
+
48
+ context "an element aggregated by multiple records" do
49
+ let(:image2) { Image.new }
50
+ it "can find all of the records that contain it" do
51
+ m = Member.create
52
+ image.ordered_members << m
53
+ image2.ordered_members << m
54
+ image.save
55
+ image2.save
56
+ expect(m.ordered_by).to contain_exactly(image2, image)
57
+ end
58
+ end
59
+ end
60
+
61
+ it "can load from solr" do
62
+ member = Member.new
63
+ subject.ordered_members << member
64
+ subject.save!
65
+ solr_doc = ActiveFedora::SolrService.query("id:#{subject.id}").first
66
+
67
+ expect { ActiveFedora::Base.load_instance_from_solr(subject.id, solr_doc) }.not_to raise_error
68
+ end
69
+
70
+ describe "#ordered_members" do
71
+ describe "<<" do
72
+ it "appends" do
73
+ member = Member.new
74
+ subject.save!
75
+ expect(subject.ordered_members << member).to eq [member]
76
+ expect(subject.ordered_members).to eq [member]
77
+ expect(subject.members).to eq [member]
78
+ expect(subject.ordered_member_proxies.to_a.length).to eq 1
79
+ subject.save!
80
+ expect(subject.head).not_to be_blank
81
+ expect(subject.reload.head).not_to be_blank
82
+ end
83
+ it "maintains member associations" do
84
+ member = Member.create
85
+ subject.ordered_members << member
86
+ subject.save
87
+ subject.reload
88
+ expect(subject.members).to eq [member]
89
+ end
90
+ end
91
+ describe "#=" do
92
+ it "sets ordered members" do
93
+ member = Member.new
94
+ member_2 = Member.new
95
+ subject.ordered_members << member
96
+ expect(subject.ordered_members).to eq [member]
97
+ subject.ordered_members = [member_2, member_2]
98
+ expect(subject.ordered_members).to eq [member_2, member_2]
99
+ # Removing from ordering is not the same as removing from aggregation.
100
+ expect(subject.members).to eq [member, member_2]
101
+ end
102
+ end
103
+ describe "+=" do
104
+ it "appends ordered members" do
105
+ member = Member.new
106
+ member_2 = Member.new
107
+ subject.ordered_members << member
108
+ expect(subject.ordered_members += [member, member_2]).to eq [member, member, member_2]
109
+ expect(subject.ordered_members).to eq [member, member, member_2]
110
+ expect(subject.ordered_member_proxies.map(&:target)).to eq [member, member, member_2]
111
+ end
112
+ end
113
+ describe "#delete_at" do
114
+ it "deletes that position" do
115
+ member = Member.new
116
+ member_2 = Member.new
117
+ subject.ordered_members += [member, member_2]
118
+
119
+ expect(subject.ordered_members.delete_at(0)).to eq member
120
+ expect(subject.ordered_members).to eq [member_2]
121
+ end
122
+ end
123
+
124
+ describe "#delete" do
125
+ let(:member) { Member.create }
126
+ let(:member_2) { Member.create }
127
+ before do
128
+ subject.ordered_members += [member, member_2, member]
129
+ subject.save!
130
+ end
131
+
132
+ context "with an object found in the list" do
133
+ it "deletes all occurences of the object" do
134
+ expect(subject.ordered_members.delete(member)).to eq member
135
+ expect(subject.ordered_members.to_a).to eq [member_2]
136
+ end
137
+ end
138
+
139
+ context "with an object not found in the list" do
140
+ it "returns nil" do
141
+ expect(subject.ordered_members.delete(Member.create)).to be_nil
142
+ expect(subject.ordered_members.to_a).to eq [member, member_2, member]
143
+ end
144
+ end
145
+ end
146
+
147
+ describe "#insert_at" do
148
+ it "adds at a given position" do
149
+ member = Member.new
150
+ member_2 = Member.new
151
+ subject.ordered_members += [member, member_2]
152
+
153
+ subject.ordered_members.insert_at(0, member_2)
154
+ expect(subject.ordered_members).to eq [member_2, member, member_2]
155
+ end
156
+ it "adds a proxy_in statement" do
157
+ member = Member.new
158
+ member_2 = Member.new
159
+ subject.ordered_members += [member, member_2]
160
+
161
+ subject.ordered_members.insert_at(0, member_2)
162
+ expect(subject.ordered_member_proxies.map(&:proxy_in).uniq).to eq [subject]
163
+ end
164
+ end
165
+ describe "lazy loading" do
166
+ it "does not instantiate every record on append" do
167
+ member = Member.new
168
+ member_2 = Member.new
169
+ subject.ordered_members += [member, member_2]
170
+ subject.save
171
+ allow(ActiveFedora::Base).to receive(:find).and_call_original
172
+
173
+ reloaded = subject.class.find(subject.id)
174
+ reloaded.ordered_members << member
175
+
176
+ expect(ActiveFedora::Base).not_to have_received(:find).with(member_2.id)
177
+ end
178
+ it "does not instantiate every record on #insert_at" do
179
+ member = Member.new
180
+ member_2 = Member.new
181
+ subject.ordered_members += [member, member_2]
182
+ subject.save
183
+ allow(ActiveFedora::Base).to receive(:find).and_call_original
184
+
185
+ reloaded = subject.class.find(subject.id)
186
+ reloaded.ordered_members.insert_at(0, member)
187
+
188
+ expect(ActiveFedora::Base).not_to have_received(:find).with(member_2.id)
189
+ end
190
+ end
191
+ end
192
+ describe "append_target" do
193
+ it "doesn't add all members" do
194
+ member = Member.new
195
+ subject.members << member
196
+ expect(subject.ordered_members).to eq []
197
+ end
198
+ it "can handle adding many objects" do
199
+ member = Member.new
200
+ 60.times do
201
+ subject.ordered_member_proxies.append_target member
202
+ end
203
+ expect(subject.ordered_member_proxies.to_a.length).to eq 60
204
+ end
205
+ it "can't add items not accepted by indirect container" do
206
+ bad_class = BadClass.new
207
+ expect { subject.ordered_member_proxies.append_target bad_class }.to raise_error ActiveFedora::AssociationTypeMismatch
208
+ end
209
+ it "adds a member if it doesn't exist in members" do
210
+ member = Member.new
211
+ subject.ordered_member_proxies.append_target member
212
+ expect(subject.members).to eq [member]
213
+ expect(subject.ordered_members).to eq [member]
214
+ end
215
+ it "doesn't add a member twice" do
216
+ member = Member.new
217
+ subject.ordered_member_proxies.append_target member
218
+ subject.ordered_member_proxies.append_target member
219
+ expect(subject.members).to eq [member]
220
+ expect(subject.ordered_members).to eq [member, member]
221
+ end
222
+ it "survives persistence" do
223
+ member = Member.new
224
+ subject.ordered_member_proxies.append_target member
225
+ subject.ordered_member_proxies.append_target member
226
+ subject.save
227
+ subject.reload
228
+ expect(subject.ordered_members).to eq [member, member]
229
+ expect(subject.list_source.resource.query([nil, ::RDF::Vocab::ORE.proxyIn, subject.resource.rdf_subject]).to_a.length).to eq 2
230
+ expect(subject.head_ids).to eq subject.list_source.head_id
231
+ expect(subject.tail_ids).to eq subject.list_source.tail_id
232
+ end
233
+ it "can add already persisted items" do
234
+ member = Member.create
235
+ subject.ordered_member_proxies.append_target member
236
+ subject.save
237
+ subject.reload
238
+ expect(subject.ordered_members).to eq [member]
239
+ end
240
+ it "can append to a pre-persisted item" do
241
+ member = Member.new
242
+ subject.ordered_member_proxies.append_target member
243
+ subject.save
244
+ subject.reload
245
+ member_2 = Member.new
246
+ subject.ordered_member_proxies.append_target member_2
247
+ subject.save
248
+ subject.reload
249
+ expect(subject.ordered_members).to eq [member, member_2]
250
+ end
251
+ end
252
+ describe "insert_target_at" do
253
+ it "can add between items" do
254
+ member = Member.new
255
+ member2 = Member.new
256
+ subject.ordered_member_proxies.append_target member
257
+ subject.ordered_member_proxies.append_target member
258
+ subject.ordered_member_proxies.insert_target_at(1, member2)
259
+ expect(subject.ordered_members).to eq [member, member2, member]
260
+ subject.save
261
+ subject.reload
262
+ expect(subject.ordered_members).to eq [member, member2, member]
263
+ subject.ordered_member_proxies.insert_target_at(2, member2)
264
+ subject.save
265
+ subject.reload
266
+ expect(subject.ordered_members).to eq [member, member2, member2, member]
267
+ end
268
+ end
269
+ describe "insert_target_id_at" do
270
+ it "can add between items" do
271
+ member = Member.create
272
+ member2 = Member.create
273
+ subject.ordered_members += [member, member2]
274
+
275
+ allow(ActiveFedora::Base).to receive(:find).and_call_original
276
+ subject.ordered_member_proxies.insert_target_id_at(1, member2.id)
277
+ expect(ActiveFedora::Base).not_to have_received(:find).with(member2.id)
278
+ expect(subject.ordered_members).to eq [member, member2, member2]
279
+ expect(ActiveFedora::Base).to have_received(:find).with(member2.id)
280
+ end
281
+ context "when given a nil id" do
282
+ it "raises an ArgumentError" do
283
+ expect { subject.ordered_member_proxies.insert_target_id_at(0, nil) }.to raise_error ArgumentError, "ID can not be nil"
284
+ end
285
+ end
286
+ context "when given an ID not in members" do
287
+ it "raises an ArgumentError" do
288
+ expect { subject.ordered_member_proxies.insert_target_id_at(0, "test") }.to raise_error "test is not a part of members"
289
+ end
290
+ end
291
+ end
292
+ describe "-=" do
293
+ it "can remove proxies" do
294
+ member = Member.new
295
+ subject.ordered_member_proxies.append_target member
296
+ subject.ordered_member_proxies -= [subject.ordered_member_proxies.last]
297
+ expect(subject.ordered_members).to eq []
298
+ expect(subject.list_source.resource.statements.to_a.length).to eq 1
299
+ end
300
+ it "can remove proxies in the middle" do
301
+ member = Member.new
302
+ member_2 = Member.new
303
+ subject.ordered_member_proxies.append_target member
304
+ subject.ordered_member_proxies.append_target member_2
305
+ subject.ordered_member_proxies.append_target member
306
+ subject.ordered_member_proxies -= [subject.ordered_member_proxies[1]]
307
+ expect(subject.ordered_members).to eq [member, member]
308
+ end
309
+ it "can remove proxies post-create" do
310
+ member = Member.new
311
+ subject.ordered_member_proxies.append_target member
312
+ subject.ordered_member_proxies.append_target member
313
+ subject.ordered_member_proxies.append_target member
314
+ subject.save
315
+ subject.reload
316
+ subject.ordered_member_proxies -= [subject.ordered_member_proxies[1]]
317
+ expect(subject.ordered_members).to eq [member, member]
318
+ subject.save
319
+ subject.reload
320
+ expect(subject.ordered_members).to eq [member, member]
321
+ # THIS NEEDS TO PASS - can't delete fragment URI resources via sparql
322
+ # update?
323
+ # Blocked by https://jira.duraspace.org/browse/FCREPO-1764
324
+ # expect(subject.list_source.resource.subjects.to_a.length).to eq 5
325
+ end
326
+ end
327
+ describe ".delete_at" do
328
+ it "can remove in the middle" do
329
+ member = Member.new
330
+ subject.ordered_member_proxies.append_target member
331
+ subject.ordered_member_proxies.append_target member
332
+ subject.ordered_member_proxies.append_target member
333
+ subject.ordered_member_proxies.delete_at(1)
334
+ expect(subject.ordered_members).to eq [member, member]
335
+ end
336
+ it "returns the node" do
337
+ member = Member.new
338
+ subject.ordered_members << member
339
+ subject.ordered_members << member
340
+ second_node = subject.ordered_member_proxies[1]
341
+ expect(subject.ordered_member_proxies.delete_at(1)).to eq second_node
342
+ end
343
+ context "when the node doesn't exist" do
344
+ it "returns nil" do
345
+ expect(subject.ordered_member_proxies.delete_at(0)).to eq nil
346
+ end
347
+ end
348
+ it "doesn't do anything if passed a bad value" do
349
+ member = Member.new
350
+ subject.ordered_member_proxies.append_target member
351
+ subject.ordered_member_proxies.append_target member
352
+ subject.ordered_member_proxies.append_target member
353
+ subject.ordered_member_proxies.delete_at(3)
354
+ subject.ordered_member_proxies.delete_at(nil)
355
+ expect(subject.ordered_members).to eq [member, member, member]
356
+ end
357
+ it "can persist a deletion" do
358
+ member = Member.new
359
+ subject.ordered_member_proxies.append_target member
360
+ subject.ordered_member_proxies.append_target member
361
+ subject.ordered_member_proxies.append_target member
362
+ expect(subject.ordered_members).to eq [member, member, member]
363
+ subject.ordered_member_proxies.delete_at(1)
364
+ subject.save
365
+ subject.reload
366
+ expect(subject.ordered_members).to eq [member, member]
367
+ end
368
+ end
369
+ end
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveFedora::Orders::ListNode do
4
+ subject { described_class.new(node_cache, rdf_subject, graph) }
5
+ let(:node_cache) { {} }
6
+ let(:rdf_subject) { RDF::URI("#bla") }
7
+ let(:graph) { RDF::Graph.new }
8
+
9
+ describe "#target" do
10
+ context "when a target is set" do
11
+ it "returns it" do
12
+ member = instance_double("member")
13
+ subject.target = member
14
+ expect(subject.target).to eq member
15
+ end
16
+ end
17
+ context "when no target is set" do
18
+ context "and it's not in the graph" do
19
+ it "returns nil" do
20
+ expect(subject.target).to eq nil
21
+ end
22
+ end
23
+ context "and it's set in the graph" do
24
+ before do
25
+ class Member < ActiveFedora::Base
26
+ end
27
+ end
28
+ after do
29
+ Object.send(:remove_const, :Member)
30
+ end
31
+ it "returns it" do
32
+ member = Member.create
33
+ graph << [rdf_subject, RDF::Vocab::ORE.proxyFor, member.resource.rdf_subject]
34
+ expect(subject.target).to eq member
35
+ end
36
+ context "and it doesn't exist" do
37
+ it "returns an AT::Resource" do
38
+ member = Member.new("testing")
39
+ graph << [rdf_subject, RDF::Vocab::ORE.proxyFor, member.resource.rdf_subject]
40
+ expect(subject.target.rdf_subject).to eq member.uri
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ describe "#target_uri" do
48
+ context "with a null target_id" do
49
+ it "returns nil" do
50
+ expect(subject.target_uri).to eq nil
51
+ end
52
+ end
53
+ context "with a target" do
54
+ before do
55
+ class Member < ActiveFedora::Base
56
+ end
57
+ end
58
+ after do
59
+ Object.send(:remove_const, :Member)
60
+ end
61
+ it "returns a built URI" do
62
+ m = Member.new
63
+ allow(m).to receive(:id).and_return("test")
64
+ subject.target = m
65
+
66
+ expect(subject.target_uri).to eq ActiveFedora::Base.translate_id_to_uri.call("test")
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#target_id" do
72
+ context "when a target is set" do
73
+ it "returns its id" do
74
+ member = instance_double("member", id: "member1")
75
+ subject.target = member
76
+ expect(subject.target_id).to eq "member1"
77
+ end
78
+ end
79
+ context "when a target is from the graph" do
80
+ before do
81
+ class Member < ActiveFedora::Base
82
+ end
83
+ end
84
+ after do
85
+ Object.send(:remove_const, :Member)
86
+ end
87
+ context "and it's cached but missing" do
88
+ it "works" do
89
+ member = Member.create
90
+ graph << [rdf_subject, RDF::Vocab::ORE.proxyFor, member.resource.rdf_subject]
91
+ allow(ActiveFedora::Base).to receive(:from_uri).and_return(ActiveTriples::Resource.new(member.resource.rdf_subject))
92
+ subject.target
93
+
94
+ expect(subject.target_id).to eq member.id
95
+ end
96
+ end
97
+ it "doesn't re-ify the target" do
98
+ member = Member.create
99
+ graph << [rdf_subject, RDF::Vocab::ORE.proxyFor, member.resource.rdf_subject]
100
+ allow(ActiveFedora::Base).to receive(:from_uri).and_call_original
101
+
102
+ expect(subject.target_id).to eq member.id
103
+ expect(ActiveFedora::Base).not_to have_received(:from_uri)
104
+ end
105
+ end
106
+ end
107
+ describe "#proxy_in_id" do
108
+ context "when a target is set" do
109
+ it "returns its id" do
110
+ member = instance_double("member", id: "member1")
111
+ subject.proxy_in = member
112
+ expect(subject.proxy_in_id).to eq "member1"
113
+ end
114
+ end
115
+ context "when a proxy_in is from the graph" do
116
+ before do
117
+ class Member < ActiveFedora::Base
118
+ end
119
+ end
120
+ after do
121
+ Object.send(:remove_const, :Member)
122
+ end
123
+ context "and it's cached but missing" do
124
+ it "works" do
125
+ member = Member.create
126
+ graph << [rdf_subject, RDF::Vocab::ORE.proxyIn, member.resource.rdf_subject]
127
+ allow(ActiveFedora::Base).to receive(:from_uri).and_return(ActiveTriples::Resource.new(member.resource.rdf_subject))
128
+ subject.target
129
+
130
+ expect(subject.proxy_in_id).to eq member.id
131
+ end
132
+ end
133
+ it "doesn't re-ify the target" do
134
+ member = Member.create
135
+ graph << [rdf_subject, RDF::Vocab::ORE.proxyIn, member.resource.rdf_subject]
136
+ allow(ActiveFedora::Base).to receive(:from_uri).and_call_original
137
+
138
+ expect(subject.proxy_in_id).to eq member.id
139
+ expect(ActiveFedora::Base).not_to have_received(:from_uri)
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "#to_graph" do
145
+ context "with no data" do
146
+ it "returns an empty graph" do
147
+ expect(subject.to_graph.statements.to_a.length).to eq 0
148
+ end
149
+ end
150
+ end
151
+ end