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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +12 -4
  4. data/lib/valkyrie/persistence/composite_persister.rb +1 -1
  5. data/lib/valkyrie/persistence/fedora/list_node.rb +42 -3
  6. data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +26 -0
  7. data/lib/valkyrie/persistence/fedora/ordered_list.rb +36 -5
  8. data/lib/valkyrie/persistence/fedora/ordered_reader.rb +6 -0
  9. data/lib/valkyrie/persistence/fedora/permissive_schema.rb +20 -1
  10. data/lib/valkyrie/persistence/fedora/persister.rb +33 -4
  11. data/lib/valkyrie/persistence/fedora/persister/alternate_identifier.rb +6 -0
  12. data/lib/valkyrie/persistence/fedora/persister/model_converter.rb +254 -4
  13. data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +250 -3
  14. data/lib/valkyrie/persistence/fedora/persister/resource_factory.rb +6 -0
  15. data/lib/valkyrie/persistence/fedora/query_service.rb +22 -4
  16. data/lib/valkyrie/persistence/memory/metadata_adapter.rb +2 -0
  17. data/lib/valkyrie/persistence/memory/persister.rb +11 -3
  18. data/lib/valkyrie/persistence/memory/query_service.rb +11 -0
  19. data/lib/valkyrie/persistence/postgres/metadata_adapter.rb +2 -0
  20. data/lib/valkyrie/persistence/postgres/orm.rb +4 -0
  21. data/lib/valkyrie/persistence/postgres/orm_converter.rb +62 -2
  22. data/lib/valkyrie/persistence/postgres/persister.rb +18 -7
  23. data/lib/valkyrie/persistence/postgres/query_service.rb +103 -11
  24. data/lib/valkyrie/persistence/postgres/resource_converter.rb +10 -0
  25. data/lib/valkyrie/persistence/postgres/resource_factory.rb +3 -0
  26. data/lib/valkyrie/persistence/solr/composite_indexer.rb +10 -0
  27. data/lib/valkyrie/persistence/solr/metadata_adapter.rb +7 -0
  28. data/lib/valkyrie/persistence/solr/model_converter.rb +137 -0
  29. data/lib/valkyrie/persistence/solr/orm_converter.rb +168 -0
  30. data/lib/valkyrie/persistence/solr/persister.rb +13 -5
  31. data/lib/valkyrie/persistence/solr/queries.rb +1 -0
  32. data/lib/valkyrie/persistence/solr/queries/default_paginator.rb +11 -1
  33. data/lib/valkyrie/persistence/solr/queries/find_all_query.rb +12 -0
  34. data/lib/valkyrie/persistence/solr/queries/find_by_alternate_identifier_query.rb +12 -0
  35. data/lib/valkyrie/persistence/solr/queries/find_by_id_query.rb +11 -0
  36. data/lib/valkyrie/persistence/solr/queries/find_inverse_references_query.rb +13 -0
  37. data/lib/valkyrie/persistence/solr/queries/find_many_by_ids_query.rb +9 -0
  38. data/lib/valkyrie/persistence/solr/queries/find_members_query.rb +23 -0
  39. data/lib/valkyrie/persistence/solr/queries/find_ordered_references_query.rb +50 -0
  40. data/lib/valkyrie/persistence/solr/queries/find_references_query.rb +15 -0
  41. data/lib/valkyrie/persistence/solr/query_service.rb +47 -14
  42. data/lib/valkyrie/persistence/solr/repository.rb +21 -4
  43. data/lib/valkyrie/persistence/solr/resource_factory.rb +2 -0
  44. data/lib/valkyrie/resource.rb +1 -0
  45. data/lib/valkyrie/specs/shared_specs.rb +1 -0
  46. data/lib/valkyrie/specs/shared_specs/persister.rb +92 -2
  47. data/lib/valkyrie/specs/shared_specs/queries.rb +12 -0
  48. data/lib/valkyrie/specs/shared_specs/solr_indexer.rb +40 -0
  49. data/lib/valkyrie/storage/fedora.rb +0 -2
  50. data/lib/valkyrie/version.rb +1 -1
  51. 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
- handle_409
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
- def handle_409
57
- raise Valkyrie::Persistence::StaleObjectError if resources.count > 1
58
- raise Valkyrie::Persistence::StaleObjectError, resources.first.id.to_s
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
@@ -50,6 +50,7 @@ module Valkyrie
50
50
  define_method("#{name}=") do |value|
51
51
  instance_variable_set("@#{name}", self.class.schema[name].call(value))
52
52
  end
53
+ type = type.meta(ordered: true) if name == :member_ids
53
54
  super(name, type)
54
55
  end
55
56
 
@@ -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.to_s)
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, "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]
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Valkyrie
3
- VERSION = "1.2.0.rc1"
3
+ VERSION = "1.2.0.rc2"
4
4
  end
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.rc1
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-09 00:00:00.000000000 Z
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