valkyrie 1.2.0.rc1 → 1.2.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +12 -4
- data/lib/valkyrie/persistence/composite_persister.rb +1 -1
- data/lib/valkyrie/persistence/fedora/list_node.rb +42 -3
- data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +26 -0
- data/lib/valkyrie/persistence/fedora/ordered_list.rb +36 -5
- data/lib/valkyrie/persistence/fedora/ordered_reader.rb +6 -0
- data/lib/valkyrie/persistence/fedora/permissive_schema.rb +20 -1
- data/lib/valkyrie/persistence/fedora/persister.rb +33 -4
- data/lib/valkyrie/persistence/fedora/persister/alternate_identifier.rb +6 -0
- data/lib/valkyrie/persistence/fedora/persister/model_converter.rb +254 -4
- data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +250 -3
- data/lib/valkyrie/persistence/fedora/persister/resource_factory.rb +6 -0
- data/lib/valkyrie/persistence/fedora/query_service.rb +22 -4
- data/lib/valkyrie/persistence/memory/metadata_adapter.rb +2 -0
- data/lib/valkyrie/persistence/memory/persister.rb +11 -3
- data/lib/valkyrie/persistence/memory/query_service.rb +11 -0
- data/lib/valkyrie/persistence/postgres/metadata_adapter.rb +2 -0
- data/lib/valkyrie/persistence/postgres/orm.rb +4 -0
- data/lib/valkyrie/persistence/postgres/orm_converter.rb +62 -2
- data/lib/valkyrie/persistence/postgres/persister.rb +18 -7
- data/lib/valkyrie/persistence/postgres/query_service.rb +103 -11
- data/lib/valkyrie/persistence/postgres/resource_converter.rb +10 -0
- data/lib/valkyrie/persistence/postgres/resource_factory.rb +3 -0
- data/lib/valkyrie/persistence/solr/composite_indexer.rb +10 -0
- data/lib/valkyrie/persistence/solr/metadata_adapter.rb +7 -0
- data/lib/valkyrie/persistence/solr/model_converter.rb +137 -0
- data/lib/valkyrie/persistence/solr/orm_converter.rb +168 -0
- data/lib/valkyrie/persistence/solr/persister.rb +13 -5
- data/lib/valkyrie/persistence/solr/queries.rb +1 -0
- data/lib/valkyrie/persistence/solr/queries/default_paginator.rb +11 -1
- data/lib/valkyrie/persistence/solr/queries/find_all_query.rb +12 -0
- data/lib/valkyrie/persistence/solr/queries/find_by_alternate_identifier_query.rb +12 -0
- data/lib/valkyrie/persistence/solr/queries/find_by_id_query.rb +11 -0
- data/lib/valkyrie/persistence/solr/queries/find_inverse_references_query.rb +13 -0
- data/lib/valkyrie/persistence/solr/queries/find_many_by_ids_query.rb +9 -0
- data/lib/valkyrie/persistence/solr/queries/find_members_query.rb +23 -0
- data/lib/valkyrie/persistence/solr/queries/find_ordered_references_query.rb +50 -0
- data/lib/valkyrie/persistence/solr/queries/find_references_query.rb +15 -0
- data/lib/valkyrie/persistence/solr/query_service.rb +47 -14
- data/lib/valkyrie/persistence/solr/repository.rb +21 -4
- data/lib/valkyrie/persistence/solr/resource_factory.rb +2 -0
- data/lib/valkyrie/resource.rb +1 -0
- data/lib/valkyrie/specs/shared_specs.rb +1 -0
- data/lib/valkyrie/specs/shared_specs/persister.rb +92 -2
- data/lib/valkyrie/specs/shared_specs/queries.rb +12 -0
- data/lib/valkyrie/specs/shared_specs/solr_indexer.rb +40 -0
- data/lib/valkyrie/storage/fedora.rb +0 -2
- data/lib/valkyrie/version.rb +1 -1
- metadata +4 -2
@@ -6,12 +6,18 @@ module Valkyrie::Persistence::Solr
|
|
6
6
|
COMMIT_PARAMS = { softCommit: true, versions: true }.freeze
|
7
7
|
|
8
8
|
attr_reader :resources, :connection, :resource_factory
|
9
|
+
|
10
|
+
# @param [Array<Valkyrie::Resource>] resources
|
11
|
+
# @param [RSolr::Client] connection
|
12
|
+
# @param [ResourceFactory] resource_factory
|
9
13
|
def initialize(resources:, connection:, resource_factory:)
|
10
14
|
@resources = resources
|
11
15
|
@connection = connection
|
12
16
|
@resource_factory = resource_factory
|
13
17
|
end
|
14
18
|
|
19
|
+
# Persist the resources into Solr
|
20
|
+
# @return [Array<Valkyrie::Resource>]
|
15
21
|
def persist
|
16
22
|
documents = resources.map do |resource|
|
17
23
|
generate_id(resource) if resource.id.blank?
|
@@ -33,29 +39,40 @@ module Valkyrie::Persistence::Solr
|
|
33
39
|
rescue RSolr::Error::Http => exception
|
34
40
|
# Error 409 conflict is returned when versions do not match
|
35
41
|
if exception.response[:status] == 409
|
36
|
-
|
42
|
+
handle_conflict
|
37
43
|
end
|
38
44
|
raise exception
|
39
45
|
end
|
40
46
|
# rubocop:enable Style/IfUnlessModifier
|
41
47
|
|
48
|
+
# Deletes a Solr Document using the ID
|
49
|
+
# @return [Array<Valkyrie::Resource>] resources which have been deleted from Solr
|
42
50
|
def delete
|
43
51
|
connection.delete_by_id resources.map { |resource| resource.id.to_s }, params: COMMIT_PARAMS
|
44
52
|
resources
|
45
53
|
end
|
46
54
|
|
55
|
+
# Given a Valkyrie Resource, generate the Hash for the Solr Document
|
56
|
+
# @param [Valkyrie::Resource] resource
|
57
|
+
# @return [Hash]
|
47
58
|
def solr_document(resource)
|
48
59
|
resource_factory.from_resource(resource: resource).to_h
|
49
60
|
end
|
50
61
|
|
62
|
+
# Given a new Valkyrie Resource, generate a random UUID and assign it to the Resource
|
63
|
+
# @param [Valkyrie::Resource] resource
|
64
|
+
# @param [String] the UUID for the new resource
|
51
65
|
def generate_id(resource)
|
52
66
|
Valkyrie.logger.warn "The Solr adapter is not meant to persist new resources, but is now generating an ID."
|
53
67
|
resource.id = SecureRandom.uuid
|
54
68
|
end
|
55
69
|
|
56
|
-
|
57
|
-
|
58
|
-
|
70
|
+
# If a 409 conflict response is encountered when attempting to commit updates to Solr, raise a StaleObjectError
|
71
|
+
# @see https://lucene.apache.org/solr/guide/updating-parts-of-documents.html#optimistic-concurrency
|
72
|
+
# @see https://tools.ietf.org/html/rfc7231#section-6.5.8
|
73
|
+
def handle_conflict
|
74
|
+
raise Valkyrie::Persistence::StaleObjectError, "One or more resources have been updated by another process." if resources.count > 1
|
75
|
+
raise Valkyrie::Persistence::StaleObjectError, "The object #{resources.first.id} has been updated by another process."
|
59
76
|
end
|
60
77
|
end
|
61
78
|
end
|
@@ -8,6 +8,8 @@ module Valkyrie::Persistence::Solr
|
|
8
8
|
attr_reader :resource_indexer, :adapter
|
9
9
|
delegate :id, to: :adapter, prefix: true
|
10
10
|
|
11
|
+
# @param [Valkyrie::Persistence::Solr::MetadataAdapter::NullIndexer] resource_indexer
|
12
|
+
# @param [Valkyrie::Persistence::Solr::MetadataAdapter] adapter
|
11
13
|
def initialize(resource_indexer:, adapter:)
|
12
14
|
@resource_indexer = resource_indexer
|
13
15
|
@adapter = adapter
|
data/lib/valkyrie/resource.rb
CHANGED
@@ -7,3 +7,4 @@ require 'valkyrie/specs/shared_specs/storage_adapter.rb'
|
|
7
7
|
require 'valkyrie/specs/shared_specs/change_set_persister.rb'
|
8
8
|
require 'valkyrie/specs/shared_specs/file.rb'
|
9
9
|
require 'valkyrie/specs/shared_specs/change_set.rb'
|
10
|
+
require 'valkyrie/specs/shared_specs/solr_indexer.rb'
|
@@ -9,6 +9,8 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
9
9
|
attribute :member_ids
|
10
10
|
attribute :nested_resource
|
11
11
|
attribute :single_value, Valkyrie::Types::String.optional
|
12
|
+
attribute :ordered_authors, Valkyrie::Types::Array.of(Valkyrie::Types::Anything).meta(ordered: true)
|
13
|
+
attribute :ordered_nested, Valkyrie::Types::Array.of(CustomResource).meta(ordered: true)
|
12
14
|
end
|
13
15
|
end
|
14
16
|
after do
|
@@ -185,6 +187,13 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
185
187
|
expect(reloaded.author.first.zone).to eq('UTC')
|
186
188
|
end
|
187
189
|
|
190
|
+
it "can store Floats" do
|
191
|
+
decimal = 5.5
|
192
|
+
book = persister.save(resource: resource_class.new(title: [decimal]))
|
193
|
+
reloaded = query_service.find_by(id: book.id)
|
194
|
+
expect(reloaded.title).to contain_exactly decimal
|
195
|
+
end
|
196
|
+
|
188
197
|
# Pending decimals support in Valkyrie
|
189
198
|
# https://github.com/samvera-labs/valkyrie/wiki/Supported-Data-Types
|
190
199
|
xit "can store Decimals" do
|
@@ -329,7 +338,7 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
329
338
|
# update the resource in the datastore to make its token stale
|
330
339
|
persister.save(resource: resource)
|
331
340
|
|
332
|
-
expect { persister.save(resource: resource) }.to raise_error(Valkyrie::Persistence::StaleObjectError, resource.id.
|
341
|
+
expect { persister.save(resource: resource) }.to raise_error(Valkyrie::Persistence::StaleObjectError, "The object #{resource.id} has been updated by another process.")
|
333
342
|
end
|
334
343
|
end
|
335
344
|
|
@@ -403,9 +412,90 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
|
|
403
412
|
persister.save(resource: resource2)
|
404
413
|
|
405
414
|
expect { persister.save_all(resources: [resource1, resource2, resource3]) }
|
406
|
-
.to raise_error(Valkyrie::Persistence::StaleObjectError, "
|
415
|
+
.to raise_error(Valkyrie::Persistence::StaleObjectError, "One or more resources have been updated by another process.")
|
407
416
|
end
|
408
417
|
end
|
409
418
|
end
|
410
419
|
end
|
420
|
+
|
421
|
+
context 'ordered properties' do
|
422
|
+
it "orders string values and returns them in the appropriate order" do
|
423
|
+
validate_order ["a", "b", "a"]
|
424
|
+
end
|
425
|
+
|
426
|
+
it "orders boolean values and returns them in the appropriate order" do
|
427
|
+
validate_order [true, false, true]
|
428
|
+
end
|
429
|
+
|
430
|
+
it "orders integer values and returns them in the appropriate order" do
|
431
|
+
validate_order [1, 2, 1]
|
432
|
+
end
|
433
|
+
|
434
|
+
it "orders date values and returns them in the appropriate order" do
|
435
|
+
now = Time.now.round(0).utc
|
436
|
+
validate_order [now, now - 3.hours, now - 1.hour]
|
437
|
+
end
|
438
|
+
|
439
|
+
it "orders URIs and returns them in the appropriate order" do
|
440
|
+
uri1 = RDF::URI("http://example.com/foo")
|
441
|
+
uri2 = RDF::URI("http://example.com/bar")
|
442
|
+
uri3 = RDF::URI("http://example.com/baz")
|
443
|
+
validate_order [uri1, uri2, uri3]
|
444
|
+
end
|
445
|
+
|
446
|
+
it "orders IDs and returns them in the appropriate order" do
|
447
|
+
page1 = persister.save(resource: resource_class.new(authors: ["Page 1"]))
|
448
|
+
page2 = persister.save(resource: resource_class.new(authors: ["Page 2"]))
|
449
|
+
page3 = persister.save(resource: resource_class.new(authors: ["Page 3"]))
|
450
|
+
validate_order [page1.id, page2.id, page3.id]
|
451
|
+
end
|
452
|
+
|
453
|
+
it "orders floating point values and returns them in the appropriate order" do
|
454
|
+
validate_order [1.123, 2.222, 1.123]
|
455
|
+
end
|
456
|
+
|
457
|
+
it "orders different types of objects together" do
|
458
|
+
validate_order [
|
459
|
+
RDF::URI("http://example.com/foo", language: :ita),
|
460
|
+
RDF::URI("http://example.com/foo", datatype: RDF::URI("http://datatype")),
|
461
|
+
1,
|
462
|
+
1.01,
|
463
|
+
"Test"
|
464
|
+
]
|
465
|
+
end
|
466
|
+
|
467
|
+
it "orders nested objects with strings" do
|
468
|
+
nested1 = resource_class.new(id: Valkyrie::ID.new("resource1"))
|
469
|
+
|
470
|
+
resource.ordered_authors = [nested1, "test"]
|
471
|
+
|
472
|
+
output = persister.save(resource: resource)
|
473
|
+
expect(output.ordered_authors[0].id).to eq nested1.id
|
474
|
+
expect(output.ordered_authors[1]).to eq "test"
|
475
|
+
end
|
476
|
+
|
477
|
+
it "orders nested objects" do
|
478
|
+
nested1 = resource_class.new(id: Valkyrie::ID.new("resource1"), authors: ["Resource 1"])
|
479
|
+
nested2 = resource_class.new(id: Valkyrie::ID.new("resource2"), authors: ["Resource 2"])
|
480
|
+
nested3 = resource_class.new(id: Valkyrie::ID.new("resource3"), authors: ["Resource 3"])
|
481
|
+
values = [nested1, nested2, nested3]
|
482
|
+
|
483
|
+
resource.ordered_nested = values
|
484
|
+
|
485
|
+
output = persister.save(resource: resource)
|
486
|
+
expect(output.ordered_nested.map(&:id)).to eq values.map(&:id)
|
487
|
+
|
488
|
+
reloaded = query_service.find_by(id: output.id)
|
489
|
+
expect(reloaded.ordered_nested.map(&:id)).to eq values.map(&:id)
|
490
|
+
end
|
491
|
+
|
492
|
+
def validate_order(values)
|
493
|
+
resource.ordered_authors = values
|
494
|
+
output = persister.save(resource: resource)
|
495
|
+
expect(output.ordered_authors).to eq(values)
|
496
|
+
|
497
|
+
reloaded = query_service.find_by(id: output.id)
|
498
|
+
expect(reloaded.ordered_authors).to eq(values)
|
499
|
+
end
|
500
|
+
end
|
411
501
|
end
|
@@ -8,6 +8,7 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
8
8
|
attribute :title
|
9
9
|
attribute :member_ids, Valkyrie::Types::Array
|
10
10
|
attribute :a_member_of
|
11
|
+
attribute :an_ordered_member_of, Valkyrie::Types::Array.meta(ordered: true)
|
11
12
|
end
|
12
13
|
class SecondResource < Valkyrie::Resource
|
13
14
|
end
|
@@ -217,6 +218,17 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
217
218
|
child = persister.save(resource: resource_class.new)
|
218
219
|
expect(query_service.find_references_by(resource: child, property: :a_member_of).to_a).to eq []
|
219
220
|
end
|
221
|
+
|
222
|
+
context "when the property is ordered" do
|
223
|
+
it "returns all references in order" do
|
224
|
+
parent = persister.save(resource: resource_class.new)
|
225
|
+
parent2 = persister.save(resource: resource_class.new)
|
226
|
+
child = persister.save(resource: resource_class.new(an_ordered_member_of: [parent.id, parent2.id, parent.id]))
|
227
|
+
persister.save(resource: resource_class.new)
|
228
|
+
|
229
|
+
expect(query_service.find_references_by(resource: child, property: :an_ordered_member_of).map(&:id).to_a).to eq [parent.id, parent2.id, parent.id]
|
230
|
+
end
|
231
|
+
end
|
220
232
|
end
|
221
233
|
|
222
234
|
describe ".find_inverse_references_by" do
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec.shared_examples 'a Valkyrie::Persistence::Solr::Indexer' do |*_flags|
|
3
|
+
let(:created_at) { Time.now.utc }
|
4
|
+
let(:attributes) do
|
5
|
+
{
|
6
|
+
created_at: created_at,
|
7
|
+
internal_resource: 'Resource',
|
8
|
+
title: ["Test", RDF::Literal.new("French", language: :fr)],
|
9
|
+
author: ["Author"],
|
10
|
+
creator: "Creator"
|
11
|
+
}
|
12
|
+
end
|
13
|
+
let(:resource) do
|
14
|
+
Resource.new(
|
15
|
+
id: "1",
|
16
|
+
internal_resource: 'Resource',
|
17
|
+
attributes: attributes
|
18
|
+
)
|
19
|
+
end
|
20
|
+
let(:indexer) { described_class.new(resource: resource) }
|
21
|
+
|
22
|
+
before do
|
23
|
+
class Resource < Valkyrie::Resource
|
24
|
+
attribute :title, Valkyrie::Types::Set
|
25
|
+
attribute :author, Valkyrie::Types::Set
|
26
|
+
attribute :birthday, Valkyrie::Types::DateTime.optional
|
27
|
+
attribute :creator, Valkyrie::Types::String
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
after do
|
32
|
+
Object.send(:remove_const, :Resource)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#to_solr' do
|
36
|
+
subject { indexer.to_solr }
|
37
|
+
|
38
|
+
it { is_expected.to be_a Hash }
|
39
|
+
end
|
40
|
+
end
|
@@ -23,8 +23,6 @@ module Valkyrie::Storage
|
|
23
23
|
# @raise Valkyrie::StorageAdapter::FileNotFound if nothing is found
|
24
24
|
def find_by(id:)
|
25
25
|
Valkyrie::StorageAdapter::StreamFile.new(id: id, io: response(id: id))
|
26
|
-
rescue ::Ldp::Gone
|
27
|
-
raise Valkyrie::StorageAdapter::FileNotFound
|
28
26
|
end
|
29
27
|
|
30
28
|
# @param file [IO]
|
data/lib/valkyrie/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: valkyrie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.0.
|
4
|
+
version: 1.2.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Trey Pendragon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-struct
|
@@ -509,6 +509,7 @@ files:
|
|
509
509
|
- lib/valkyrie/persistence/solr/queries/find_inverse_references_query.rb
|
510
510
|
- lib/valkyrie/persistence/solr/queries/find_many_by_ids_query.rb
|
511
511
|
- lib/valkyrie/persistence/solr/queries/find_members_query.rb
|
512
|
+
- lib/valkyrie/persistence/solr/queries/find_ordered_references_query.rb
|
512
513
|
- lib/valkyrie/persistence/solr/queries/find_references_query.rb
|
513
514
|
- lib/valkyrie/persistence/solr/query_service.rb
|
514
515
|
- lib/valkyrie/persistence/solr/repository.rb
|
@@ -524,6 +525,7 @@ files:
|
|
524
525
|
- lib/valkyrie/specs/shared_specs/persister.rb
|
525
526
|
- lib/valkyrie/specs/shared_specs/queries.rb
|
526
527
|
- lib/valkyrie/specs/shared_specs/resource.rb
|
528
|
+
- lib/valkyrie/specs/shared_specs/solr_indexer.rb
|
527
529
|
- lib/valkyrie/specs/shared_specs/storage_adapter.rb
|
528
530
|
- lib/valkyrie/storage.rb
|
529
531
|
- lib/valkyrie/storage/disk.rb
|