active-fedora 9.10.4 → 9.11.0

Sign up to get free protection for your applications and to get access to all the features.
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