valkyrie 0.1.0 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.ctags +2 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +3 -0
- data/CHANGELOG.md +43 -0
- data/Gemfile +0 -4
- data/LICENSE +15 -0
- data/README.md +13 -8
- data/Rakefile +15 -1
- data/bin/jetty_wait +14 -0
- data/bin/rspec +29 -0
- data/browserslist +3 -0
- data/circle.yml +17 -0
- data/config/fedora.yml +10 -0
- data/db/migrate/20161007101725_create_orm_resources.rb +9 -1
- data/db/migrate/20171011224121_create_path_gin_index.rb +6 -0
- data/db/migrate/20171204224121_create_internal_resource_index.rb +6 -0
- data/db/migrate/20180212092225_create_updated_at_index.rb +6 -0
- data/lib/generators/valkyrie/templates/resource_spec.rb.erb +1 -1
- data/lib/valkyrie.rb +1 -7
- data/lib/valkyrie/change_set.rb +21 -7
- data/lib/valkyrie/engine.rb +2 -0
- data/lib/valkyrie/id.rb +1 -0
- data/lib/valkyrie/indexers/access_controls_indexer.rb +50 -6
- data/lib/valkyrie/metadata_adapter.rb +29 -1
- data/lib/valkyrie/persistence.rb +27 -0
- data/lib/valkyrie/persistence/buffered_persister.rb +17 -1
- data/lib/valkyrie/persistence/composite_persister.rb +14 -2
- data/lib/valkyrie/persistence/custom_query_container.rb +63 -0
- data/lib/valkyrie/persistence/delete_tracking_buffer.rb +8 -0
- data/lib/valkyrie/persistence/fedora.rb +3 -0
- data/lib/valkyrie/persistence/fedora/list_node.rb +5 -2
- data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +13 -11
- data/lib/valkyrie/persistence/fedora/ordered_list.rb +2 -2
- data/lib/valkyrie/persistence/fedora/ordered_reader.rb +3 -2
- data/lib/valkyrie/persistence/fedora/permissive_schema.rb +75 -0
- data/lib/valkyrie/persistence/fedora/persister.rb +22 -0
- data/lib/valkyrie/persistence/fedora/persister/model_converter.rb +110 -25
- data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +49 -17
- data/lib/valkyrie/persistence/fedora/persister/resource_factory.rb +2 -0
- data/lib/valkyrie/persistence/fedora/query_service.rb +46 -3
- data/lib/valkyrie/persistence/memory.rb +5 -0
- data/lib/valkyrie/persistence/memory/metadata_adapter.rb +6 -1
- data/lib/valkyrie/persistence/memory/persister.rb +19 -1
- data/lib/valkyrie/persistence/memory/query_service.rb +49 -8
- data/lib/valkyrie/persistence/postgres.rb +2 -0
- data/lib/valkyrie/persistence/postgres/metadata_adapter.rb +8 -1
- data/lib/valkyrie/persistence/postgres/orm.rb +1 -0
- data/lib/valkyrie/persistence/postgres/orm/resource.rb +12 -0
- data/lib/valkyrie/persistence/postgres/orm_converter.rb +99 -74
- data/lib/valkyrie/persistence/postgres/persister.rb +16 -0
- data/lib/valkyrie/persistence/postgres/query_service.rb +94 -6
- data/lib/valkyrie/persistence/postgres/resource_converter.rb +3 -1
- data/lib/valkyrie/persistence/postgres/resource_factory.rb +5 -5
- data/lib/valkyrie/persistence/solr.rb +2 -0
- data/lib/valkyrie/persistence/solr/composite_indexer.rb +29 -0
- data/lib/valkyrie/persistence/solr/metadata_adapter.rb +26 -1
- data/lib/valkyrie/persistence/solr/model_converter.rb +38 -8
- data/lib/valkyrie/persistence/solr/orm_converter.rb +43 -20
- data/lib/valkyrie/persistence/solr/persister.rb +16 -0
- data/lib/valkyrie/persistence/solr/queries.rb +3 -0
- data/lib/valkyrie/persistence/solr/queries/default_paginator.rb +2 -0
- data/lib/valkyrie/persistence/solr/queries/find_all_query.rb +3 -1
- data/lib/valkyrie/persistence/solr/queries/find_by_id_query.rb +4 -2
- data/lib/valkyrie/persistence/solr/queries/find_inverse_references_query.rb +2 -0
- data/lib/valkyrie/persistence/solr/queries/find_many_by_ids_query.rb +21 -0
- data/lib/valkyrie/persistence/solr/queries/find_members_query.rb +13 -5
- data/lib/valkyrie/persistence/solr/queries/find_references_query.rb +7 -3
- data/lib/valkyrie/persistence/solr/query_service.rb +30 -2
- data/lib/valkyrie/persistence/solr/repository.rb +14 -2
- data/lib/valkyrie/persistence/solr/resource_factory.rb +3 -1
- data/lib/valkyrie/resource.rb +11 -4
- data/lib/valkyrie/resource/access_controls.rb +13 -0
- data/lib/valkyrie/specs/shared_specs.rb +1 -2
- data/lib/valkyrie/specs/shared_specs/change_set.rb +75 -0
- data/lib/valkyrie/specs/shared_specs/metadata_adapter.rb +3 -0
- data/lib/valkyrie/specs/shared_specs/persister.rb +145 -15
- data/lib/valkyrie/specs/shared_specs/queries.rb +153 -27
- data/lib/valkyrie/specs/shared_specs/storage_adapter.rb +8 -3
- data/lib/valkyrie/storage.rb +29 -0
- data/lib/valkyrie/storage/disk.rb +17 -5
- data/lib/valkyrie/storage/fedora.rb +14 -1
- data/lib/valkyrie/storage/memory.rb +15 -2
- data/lib/valkyrie/storage_adapter.rb +26 -4
- data/lib/valkyrie/types.rb +65 -7
- data/lib/valkyrie/version.rb +1 -1
- data/solr/config/_rest_managed.json +3 -0
- data/solr/config/admin-extra.html +31 -0
- data/solr/config/elevate.xml +36 -0
- data/solr/config/mapping-ISOLatin1Accent.txt +246 -0
- data/solr/config/protwords.txt +21 -0
- data/solr/config/schema.xml +366 -0
- data/solr/config/scripts.conf +24 -0
- data/solr/config/solrconfig.xml +322 -0
- data/solr/config/spellings.txt +2 -0
- data/solr/config/stopwords.txt +58 -0
- data/solr/config/stopwords_en.txt +58 -0
- data/solr/config/synonyms.txt +31 -0
- data/solr/config/xslt/example.xsl +132 -0
- data/solr/config/xslt/example_atom.xsl +67 -0
- data/solr/config/xslt/example_rss.xsl +66 -0
- data/solr/config/xslt/luke.xsl +337 -0
- data/solr/solr.xml +35 -0
- data/tasks/dev.rake +66 -0
- data/valkyrie.gemspec +6 -6
- metadata +58 -63
- data/lib/valkyrie/decorators/decorator_list.rb +0 -15
- data/lib/valkyrie/decorators/decorator_with_arguments.rb +0 -14
- data/lib/valkyrie/derivative_service.rb +0 -42
- data/lib/valkyrie/file_characterization_service.rb +0 -42
- data/lib/valkyrie/local_file_service.rb +0 -11
- data/lib/valkyrie/persist_derivatives.rb +0 -29
- data/lib/valkyrie/persistence/postgres/queries.rb +0 -8
- data/lib/valkyrie/persistence/postgres/queries/find_inverse_references_query.rb +0 -31
- data/lib/valkyrie/persistence/postgres/queries/find_members_query.rb +0 -33
- data/lib/valkyrie/persistence/postgres/queries/find_references_query.rb +0 -33
- data/lib/valkyrie/specs/shared_specs/derivative_service.rb +0 -30
- data/lib/valkyrie/specs/shared_specs/file_characterization_service.rb +0 -33
@@ -7,4 +7,7 @@ RSpec.shared_examples 'a Valkyrie::MetadataAdapter' do |passed_adapter|
|
|
7
7
|
subject { passed_adapter || adapter }
|
8
8
|
it { is_expected.to respond_to(:persister).with(0).arguments }
|
9
9
|
it { is_expected.to respond_to(:query_service).with(0).arguments }
|
10
|
+
it "caches query_service so it can register custom queries" do
|
11
|
+
expect(subject.query_service.custom_queries.query_handlers.object_id).to eq subject.query_service.custom_queries.query_handlers.object_id
|
12
|
+
end
|
10
13
|
end
|
@@ -9,6 +9,7 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
9
9
|
attribute :author
|
10
10
|
attribute :member_ids
|
11
11
|
attribute :nested_resource
|
12
|
+
attribute :single_value, Valkyrie::Types::String
|
12
13
|
end
|
13
14
|
end
|
14
15
|
after do
|
@@ -24,7 +25,15 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
24
25
|
it { is_expected.to respond_to(:delete).with_keywords(:resource) }
|
25
26
|
|
26
27
|
it "can save a resource" do
|
27
|
-
expect(
|
28
|
+
expect(resource).not_to be_persisted
|
29
|
+
saved = persister.save(resource: resource)
|
30
|
+
expect(saved).to be_persisted
|
31
|
+
expect(saved.id).not_to be_blank
|
32
|
+
end
|
33
|
+
|
34
|
+
it "does not save non-array properties" do
|
35
|
+
resource.single_value = "A Single Value"
|
36
|
+
expect { persister.save(resource: resource) }.to raise_error ::Valkyrie::Persistence::UnsupportedDatatype
|
28
37
|
end
|
29
38
|
|
30
39
|
it "can save multiple resources at once" do
|
@@ -74,33 +83,87 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
74
83
|
expect(book.updated_at).not_to be_kind_of Array
|
75
84
|
end
|
76
85
|
|
86
|
+
it "can handle Boolean RDF properties" do
|
87
|
+
boolean_rdf = RDF::Literal.new(false)
|
88
|
+
book = persister.save(resource: resource_class.new(title: [boolean_rdf]))
|
89
|
+
reloaded = query_service.find_by(id: book.id)
|
90
|
+
expect(reloaded.title).to contain_exactly boolean_rdf
|
91
|
+
end
|
92
|
+
|
93
|
+
it "can handle custom-typed RDF properties" do
|
94
|
+
custom_rdf = RDF::Literal.new("Test", datatype: RDF::URI.parse("http://my_made_up_type"))
|
95
|
+
book = persister.save(resource: resource_class.new(title: [custom_rdf]))
|
96
|
+
reloaded = query_service.find_by(id: book.id)
|
97
|
+
expect(reloaded.title).to contain_exactly custom_rdf
|
98
|
+
end
|
99
|
+
|
100
|
+
it "can handle Date RDF properties" do
|
101
|
+
date_rdf = RDF::Literal.new(Date.current)
|
102
|
+
book = persister.save(resource: resource_class.new(title: [date_rdf]))
|
103
|
+
reloaded = query_service.find_by(id: book.id)
|
104
|
+
expect(reloaded.title).to contain_exactly date_rdf
|
105
|
+
end
|
106
|
+
|
107
|
+
it "can handle DateTime RDF properties" do
|
108
|
+
datetime_rdf = RDF::Literal.new(DateTime.current)
|
109
|
+
book = persister.save(resource: resource_class.new(title: [datetime_rdf]))
|
110
|
+
reloaded = query_service.find_by(id: book.id)
|
111
|
+
expect(reloaded.title).to contain_exactly datetime_rdf
|
112
|
+
end
|
113
|
+
|
114
|
+
it "can handle Decimal RDF properties" do
|
115
|
+
decimal_rdf = RDF::Literal.new(BigDecimal(5.5, 10))
|
116
|
+
book = persister.save(resource: resource_class.new(title: [decimal_rdf]))
|
117
|
+
reloaded = query_service.find_by(id: book.id)
|
118
|
+
expect(reloaded.title).to contain_exactly decimal_rdf
|
119
|
+
end
|
120
|
+
|
121
|
+
it "can handle Double RDF properties" do
|
122
|
+
double_rdf = RDF::Literal.new(5.5)
|
123
|
+
book = persister.save(resource: resource_class.new(title: [double_rdf]))
|
124
|
+
reloaded = query_service.find_by(id: book.id)
|
125
|
+
expect(reloaded.title).to contain_exactly double_rdf
|
126
|
+
end
|
127
|
+
|
128
|
+
it "can handle Integer RDF properties" do
|
129
|
+
int_rdf = RDF::Literal.new(17)
|
130
|
+
book = persister.save(resource: resource_class.new(title: [int_rdf]))
|
131
|
+
reloaded = query_service.find_by(id: book.id)
|
132
|
+
expect(reloaded.title).to contain_exactly int_rdf
|
133
|
+
end
|
134
|
+
|
77
135
|
it "can handle language-typed RDF properties" do
|
78
|
-
|
136
|
+
language_rdf = RDF::Literal.new("Test", language: :fr)
|
137
|
+
book = persister.save(resource: resource_class.new(title: ["Test1", language_rdf]))
|
79
138
|
reloaded = query_service.find_by(id: book.id)
|
80
|
-
expect(reloaded.title).to contain_exactly "Test1",
|
139
|
+
expect(reloaded.title).to contain_exactly "Test1", language_rdf
|
81
140
|
end
|
82
141
|
|
83
|
-
it "can
|
84
|
-
|
85
|
-
book = persister.save(resource: resource_class.new(title: [
|
142
|
+
it "can handle Time RDF properties" do
|
143
|
+
time_rdf = RDF::Literal.new(Time.current)
|
144
|
+
book = persister.save(resource: resource_class.new(title: [time_rdf]))
|
86
145
|
reloaded = query_service.find_by(id: book.id)
|
87
|
-
expect(reloaded.title).to contain_exactly
|
88
|
-
expect([shared_title.id, Valkyrie::ID.new("adapter://1"), "test"]).to contain_exactly(*reloaded.title)
|
146
|
+
expect(reloaded.title).to contain_exactly time_rdf
|
89
147
|
end
|
90
148
|
|
91
|
-
|
92
|
-
|
149
|
+
# https://github.com/samvera-labs/valkyrie/wiki/Supported-Data-Types
|
150
|
+
it "can store booleans" do
|
151
|
+
boolean = [false, true]
|
152
|
+
book = persister.save(resource: resource_class.new(title: boolean))
|
93
153
|
reloaded = query_service.find_by(id: book.id)
|
94
|
-
expect(reloaded.title).to contain_exactly
|
154
|
+
expect(reloaded.title).to contain_exactly(*boolean)
|
95
155
|
end
|
96
156
|
|
97
|
-
|
98
|
-
|
157
|
+
# Pending date support in Valkyrie
|
158
|
+
# https://github.com/samvera-labs/valkyrie/wiki/Supported-Data-Types
|
159
|
+
xit "can store Dates" do
|
160
|
+
date = Date.current
|
161
|
+
book = persister.save(resource: resource_class.new(title: [date]))
|
99
162
|
reloaded = query_service.find_by(id: book.id)
|
100
|
-
expect(reloaded.title).to contain_exactly
|
163
|
+
expect(reloaded.title).to contain_exactly date
|
101
164
|
end
|
102
165
|
|
103
|
-
it "can store
|
166
|
+
it "can store DateTimes" do
|
104
167
|
time1 = DateTime.current
|
105
168
|
time2 = Time.current.in_time_zone
|
106
169
|
book = persister.save(resource: resource_class.new(title: [time1], author: [time2]))
|
@@ -113,6 +176,66 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
113
176
|
expect(reloaded.author.first.zone).to eq('UTC')
|
114
177
|
end
|
115
178
|
|
179
|
+
# Pending decimals support in Valkyrie
|
180
|
+
# https://github.com/samvera-labs/valkyrie/wiki/Supported-Data-Types
|
181
|
+
xit "can store Decimals" do
|
182
|
+
decimal = BigDecimal(5.5, 10)
|
183
|
+
book = persister.save(resource: resource_class.new(title: [decimal]))
|
184
|
+
reloaded = query_service.find_by(id: book.id)
|
185
|
+
expect(reloaded.title).to contain_exactly decimal
|
186
|
+
end
|
187
|
+
|
188
|
+
# Pending doubles support in Valkyrie
|
189
|
+
# https://github.com/samvera-labs/valkyrie/wiki/Supported-Data-Types
|
190
|
+
xit "can store doubles" do
|
191
|
+
book = persister.save(resource: resource_class.new(title: [1.5]))
|
192
|
+
reloaded = query_service.find_by(id: book.id)
|
193
|
+
expect(reloaded.title).to contain_exactly 1.5
|
194
|
+
end
|
195
|
+
|
196
|
+
it "can store integers" do
|
197
|
+
book = persister.save(resource: resource_class.new(title: [1]))
|
198
|
+
reloaded = query_service.find_by(id: book.id)
|
199
|
+
expect(reloaded.title).to contain_exactly 1
|
200
|
+
end
|
201
|
+
|
202
|
+
# Pending time support in Valkyrie
|
203
|
+
# currently millisecond precision is lost is postgres and solr
|
204
|
+
#
|
205
|
+
# https://github.com/samvera-labs/valkyrie/wiki/Supported-Data-Types
|
206
|
+
xit "can store Times" do
|
207
|
+
time = Time.current
|
208
|
+
book = persister.save(resource: resource_class.new(title: [time]))
|
209
|
+
reloaded = query_service.find_by(id: book.id)
|
210
|
+
expect(reloaded.title).to contain_exactly time.utc
|
211
|
+
end
|
212
|
+
|
213
|
+
it "can store ::RDF::URIs" do
|
214
|
+
book = persister.save(resource: resource_class.new(title: [::RDF::URI("http://example.com")]))
|
215
|
+
reloaded = query_service.find_by(id: book.id)
|
216
|
+
expect(reloaded.title).to contain_exactly RDF::URI("http://example.com")
|
217
|
+
end
|
218
|
+
|
219
|
+
it "can store Valkyrie::IDs" do
|
220
|
+
shared_title = persister.save(resource: resource_class.new(id: "test"))
|
221
|
+
book = persister.save(resource: resource_class.new(title: [shared_title.id, Valkyrie::ID.new("adapter://1"), "test"]))
|
222
|
+
reloaded = query_service.find_by(id: book.id)
|
223
|
+
expect(reloaded.title).to contain_exactly(shared_title.id, Valkyrie::ID.new("adapter://1"), "test")
|
224
|
+
expect([shared_title.id, Valkyrie::ID.new("adapter://1"), "test"]).to contain_exactly(*reloaded.title)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "can override default id generation with a provided id" do
|
228
|
+
id = SecureRandom.uuid
|
229
|
+
book = persister.save(resource: resource_class.new(id: id))
|
230
|
+
reloaded = query_service.find_by(id: book.id)
|
231
|
+
expect(reloaded.id).to eq Valkyrie::ID.new(id)
|
232
|
+
expect(reloaded).to be_persisted
|
233
|
+
expect(reloaded.created_at).not_to be_blank
|
234
|
+
expect(reloaded.updated_at).not_to be_blank
|
235
|
+
expect(reloaded.created_at).not_to be_kind_of Array
|
236
|
+
expect(reloaded.updated_at).not_to be_kind_of Array
|
237
|
+
end
|
238
|
+
|
116
239
|
context "parent tests" do
|
117
240
|
let(:book) { persister.save(resource: resource_class.new) }
|
118
241
|
let(:book2) { persister.save(resource: resource_class.new) }
|
@@ -151,4 +274,11 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
151
274
|
persister.delete(resource: persisted)
|
152
275
|
expect { query_service.find_by(id: persisted.id) }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
|
153
276
|
end
|
277
|
+
|
278
|
+
it "can delete all objects" do
|
279
|
+
resource2 = resource_class.new
|
280
|
+
persister.save_all(resources: [resource, resource2])
|
281
|
+
persister.wipe!
|
282
|
+
expect(query_service.find_all.to_a.length).to eq 0
|
283
|
+
end
|
154
284
|
end
|
@@ -6,7 +6,7 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
6
6
|
class CustomResource < Valkyrie::Resource
|
7
7
|
attribute :id, Valkyrie::Types::ID.optional
|
8
8
|
attribute :title
|
9
|
-
attribute :member_ids
|
9
|
+
attribute :member_ids, Valkyrie::Types::Array
|
10
10
|
attribute :a_member_of
|
11
11
|
end
|
12
12
|
class SecondResource < Valkyrie::Resource
|
@@ -18,14 +18,15 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
18
18
|
Object.send(:remove_const, :SecondResource)
|
19
19
|
end
|
20
20
|
let(:resource_class) { CustomResource }
|
21
|
-
let(:query_service) { adapter.query_service }
|
21
|
+
let(:query_service) { adapter.query_service } unless defined? query_service
|
22
22
|
let(:persister) { adapter.persister }
|
23
23
|
subject { adapter.query_service }
|
24
24
|
|
25
25
|
it { is_expected.to respond_to(:find_all).with(0).arguments }
|
26
26
|
it { is_expected.to respond_to(:find_all_of_model).with_keywords(:model) }
|
27
27
|
it { is_expected.to respond_to(:find_by).with_keywords(:id) }
|
28
|
-
it { is_expected.to respond_to(:
|
28
|
+
it { is_expected.to respond_to(:find_many_by_ids).with_keywords(:ids) }
|
29
|
+
it { is_expected.to respond_to(:find_members).with_keywords(:resource, :model) }
|
29
30
|
it { is_expected.to respond_to(:find_references_by).with_keywords(:resource, :property) }
|
30
31
|
it { is_expected.to respond_to(:find_inverse_references_by).with_keywords(:resource, :property) }
|
31
32
|
it { is_expected.to respond_to(:find_parents).with_keywords(:resource) }
|
@@ -52,31 +53,117 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
52
53
|
end
|
53
54
|
|
54
55
|
describe ".find_by" do
|
55
|
-
it "returns a resource by id" do
|
56
|
+
it "returns a resource by id or string representation of an id" do
|
56
57
|
resource = persister.save(resource: resource_class.new)
|
57
58
|
|
58
|
-
|
59
|
+
found = query_service.find_by(id: resource.id)
|
60
|
+
expect(found.id).to eq resource.id
|
61
|
+
expect(found).to be_persisted
|
62
|
+
|
63
|
+
found = query_service.find_by(id: resource.id.to_s)
|
64
|
+
expect(found.id).to eq resource.id
|
65
|
+
expect(found).to be_persisted
|
59
66
|
end
|
67
|
+
|
60
68
|
it "returns a Valkyrie::Persistence::ObjectNotFoundError for a non-found ID" do
|
61
|
-
expect { query_service.find_by(id: "123123123") }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
|
69
|
+
expect { query_service.find_by(id: Valkyrie::ID.new("123123123")) }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'raises an error if the id is not a Valkyrie::ID or a string' do
|
73
|
+
expect { query_service.find_by(id: 123) }.to raise_error ArgumentError
|
62
74
|
end
|
63
75
|
end
|
64
76
|
|
65
|
-
describe ".
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
77
|
+
describe ".find_many_by_ids" do
|
78
|
+
let!(:resource) { persister.save(resource: resource_class.new) }
|
79
|
+
let!(:resource2) { persister.save(resource: resource_class.new) }
|
80
|
+
let!(:resource3) { persister.save(resource: resource_class.new) }
|
81
|
+
|
82
|
+
it "returns an array of resources by ids or string representation ids" do
|
83
|
+
found = query_service.find_many_by_ids(ids: [resource.id, resource2.id])
|
84
|
+
expect(found.map(&:id)).to contain_exactly resource.id, resource2.id
|
70
85
|
|
71
|
-
|
72
|
-
expect(
|
86
|
+
found = query_service.find_many_by_ids(ids: [resource.id.to_s, resource2.id.to_s])
|
87
|
+
expect(found.map(&:id)).to contain_exactly resource.id, resource2.id
|
73
88
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
89
|
+
|
90
|
+
it "returns a partial list for a non-found ID" do
|
91
|
+
found = query_service.find_many_by_ids(ids: [resource.id, Valkyrie::ID.new("123123123")])
|
92
|
+
expect(found.map(&:id)).to contain_exactly resource.id
|
77
93
|
end
|
78
|
-
|
79
|
-
|
94
|
+
|
95
|
+
it "returns an empty list if no ids were found" do
|
96
|
+
found = query_service.find_many_by_ids(ids: [Valkyrie::ID.new("you-cannot-find-me"), Valkyrie::ID.new("123123123")])
|
97
|
+
expect(found.map(&:id)).to eq []
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'raises an error if any id is not a Valkyrie::ID or a string' do
|
101
|
+
expect { query_service.find_many_by_ids(ids: [resource.id, 123]) }.to raise_error ArgumentError
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe ".find_members" do
|
106
|
+
context "without filtering by model" do
|
107
|
+
subject { query_service.find_members(resource: parent) }
|
108
|
+
|
109
|
+
context "when the object has members" do
|
110
|
+
let!(:child1) { persister.save(resource: resource_class.new) }
|
111
|
+
let!(:child2) { persister.save(resource: resource_class.new) }
|
112
|
+
let(:parent) { persister.save(resource: resource_class.new(member_ids: [child2.id, child1.id])) }
|
113
|
+
|
114
|
+
it "returns all a resource's members in order" do
|
115
|
+
expect(subject.map(&:id).to_a).to eq [child2.id, child1.id]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "when there's no resource ID" do
|
120
|
+
let(:parent) { resource_class.new }
|
121
|
+
|
122
|
+
it "doesn't error" do
|
123
|
+
expect(subject).not_to eq nil
|
124
|
+
expect(subject.to_a).to eq []
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when there are no members" do
|
129
|
+
let(:parent) { persister.save(resource: resource_class.new) }
|
130
|
+
|
131
|
+
it "returns an empty array" do
|
132
|
+
expect(subject.to_a).to eq []
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when the model doesn't have member_ids" do
|
137
|
+
let(:parent) { persister.save(resource: SecondResource.new) }
|
138
|
+
|
139
|
+
it "returns an empty array" do
|
140
|
+
expect(subject.to_a).to eq []
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "filtering by model" do
|
146
|
+
subject { query_service.find_members(resource: parent, model: SecondResource) }
|
147
|
+
|
148
|
+
context "when the object has members" do
|
149
|
+
let(:child1) { persister.save(resource: SecondResource.new) }
|
150
|
+
let(:child2) { persister.save(resource: resource_class.new) }
|
151
|
+
let(:child3) { persister.save(resource: SecondResource.new) }
|
152
|
+
let(:parent) { persister.save(resource: resource_class.new(member_ids: [child3.id, child2.id, child1.id])) }
|
153
|
+
|
154
|
+
it "returns all a resource's members in order" do
|
155
|
+
expect(subject.map(&:id).to_a).to eq [child3.id, child1.id]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "when there are no members that match the filter" do
|
160
|
+
let(:child1) { persister.save(resource: resource_class.new) }
|
161
|
+
let(:parent) { persister.save(resource: resource_class.new(member_ids: [child1.id])) }
|
162
|
+
|
163
|
+
it "returns an empty array" do
|
164
|
+
expect(subject.to_a).to eq []
|
165
|
+
end
|
166
|
+
end
|
80
167
|
end
|
81
168
|
end
|
82
169
|
|
@@ -95,18 +182,27 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
95
182
|
end
|
96
183
|
|
97
184
|
describe ".find_inverse_references_by" do
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
185
|
+
context "when the resource is saved" do
|
186
|
+
it "returns everything which references the given resource by the given property" do
|
187
|
+
parent = persister.save(resource: resource_class.new)
|
188
|
+
child = persister.save(resource: resource_class.new(a_member_of: [parent.id]))
|
189
|
+
persister.save(resource: resource_class.new)
|
190
|
+
persister.save(resource: SecondResource.new)
|
191
|
+
|
192
|
+
expect(query_service.find_inverse_references_by(resource: parent, property: :a_member_of).map(&:id).to_a).to eq [child.id]
|
193
|
+
end
|
194
|
+
it "returns an empty array if there are none" do
|
195
|
+
parent = persister.save(resource: resource_class.new)
|
103
196
|
|
104
|
-
|
197
|
+
expect(query_service.find_inverse_references_by(resource: parent, property: :a_member_of).to_a).to eq []
|
198
|
+
end
|
105
199
|
end
|
106
|
-
|
107
|
-
|
200
|
+
context "when the resource is not saved" do
|
201
|
+
it "raises an error" do
|
202
|
+
parent = resource_class.new
|
108
203
|
|
109
|
-
|
204
|
+
expect { query_service.find_inverse_references_by(resource: parent, property: :a_member_of).to_a }.to raise_error ArgumentError
|
205
|
+
end
|
110
206
|
end
|
111
207
|
end
|
112
208
|
|
@@ -124,5 +220,35 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
124
220
|
|
125
221
|
expect(query_service.find_parents(resource: child1).to_a).to eq []
|
126
222
|
end
|
223
|
+
|
224
|
+
context "when the model doesn't have member_ids" do
|
225
|
+
let(:child1) { persister.save(resource: SecondResource.new) }
|
226
|
+
|
227
|
+
it "returns an empty array if there are none" do
|
228
|
+
expect(query_service.find_parents(resource: child1).to_a).to eq []
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe ".register_query_handler" do
|
234
|
+
it "can register a query handler" do
|
235
|
+
class QueryHandler
|
236
|
+
def self.queries
|
237
|
+
[:find_by_user_id]
|
238
|
+
end
|
239
|
+
|
240
|
+
attr_reader :query_service
|
241
|
+
def initialize(query_service:)
|
242
|
+
@query_service = query_service
|
243
|
+
end
|
244
|
+
|
245
|
+
def find_by_user_id
|
246
|
+
1
|
247
|
+
end
|
248
|
+
end
|
249
|
+
query_service.custom_queries.register_query_handler(QueryHandler)
|
250
|
+
expect(query_service.custom_queries).to respond_to :find_by_user_id
|
251
|
+
expect(query_service.custom_queries.find_by_user_id).to eq 1
|
252
|
+
end
|
127
253
|
end
|
128
254
|
end
|
@@ -15,13 +15,14 @@ RSpec.shared_examples 'a Valkyrie::StorageAdapter' do
|
|
15
15
|
subject { storage_adapter }
|
16
16
|
it { is_expected.to respond_to(:handles?).with_keywords(:id) }
|
17
17
|
it { is_expected.to respond_to(:find_by).with_keywords(:id) }
|
18
|
-
it { is_expected.to respond_to(:
|
18
|
+
it { is_expected.to respond_to(:delete).with_keywords(:id) }
|
19
|
+
it { is_expected.to respond_to(:upload).with_keywords(:file, :resource, :original_filename) }
|
19
20
|
|
20
|
-
it "can upload, validate,
|
21
|
+
it "can upload, validate, re-fetch, and delete a file" do
|
21
22
|
resource = CustomResource.new(id: "test")
|
22
23
|
sha1 = Digest::SHA1.file(file).to_s
|
23
24
|
size = file.size
|
24
|
-
expect(uploaded_file = storage_adapter.upload(file: file, resource: resource)).to be_kind_of Valkyrie::StorageAdapter::File
|
25
|
+
expect(uploaded_file = storage_adapter.upload(file: file, original_filename: 'foo.jpg', resource: resource)).to be_kind_of Valkyrie::StorageAdapter::File
|
25
26
|
|
26
27
|
expect(uploaded_file).to respond_to(:checksum).with_keywords(:digests)
|
27
28
|
expect(uploaded_file).to respond_to(:valid?).with_keywords(:size, :digests)
|
@@ -40,5 +41,9 @@ RSpec.shared_examples 'a Valkyrie::StorageAdapter' do
|
|
40
41
|
expect(file.stream).to respond_to(:read)
|
41
42
|
new_file = Tempfile.new
|
42
43
|
expect { IO.copy_stream(file, new_file) }.not_to raise_error
|
44
|
+
|
45
|
+
storage_adapter.delete(id: uploaded_file.id)
|
46
|
+
expect { storage_adapter.find_by(id: uploaded_file.id) }.to raise_error Valkyrie::StorageAdapter::FileNotFound
|
47
|
+
expect { storage_adapter.find_by(id: Valkyrie::ID.new("noexist")) }.to raise_error Valkyrie::StorageAdapter::FileNotFound
|
43
48
|
end
|
44
49
|
end
|