valkyrie 2.0.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +65 -56
  3. data/.lando.yml +58 -0
  4. data/.rubocop.yml +4 -1
  5. data/.tool-versions +1 -1
  6. data/Appraisals +4 -4
  7. data/CHANGELOG.md +134 -0
  8. data/README.md +21 -49
  9. data/Rakefile +26 -20
  10. data/db/config.yml +3 -10
  11. data/db/schema.rb +0 -40
  12. data/gemfiles/activerecord_5_2.gemfile +2 -0
  13. data/gemfiles/{activerecord_5_1.gemfile → activerecord_6_0.gemfile} +3 -1
  14. data/lib/generators/valkyrie/resource_generator.rb +3 -3
  15. data/lib/valkyrie.rb +33 -15
  16. data/lib/valkyrie/change_set.rb +3 -3
  17. data/lib/valkyrie/id.rb +26 -3
  18. data/lib/valkyrie/indexers/access_controls_indexer.rb +17 -17
  19. data/lib/valkyrie/logging.rb +72 -0
  20. data/lib/valkyrie/persistence/composite_persister.rb +1 -1
  21. data/lib/valkyrie/persistence/fedora.rb +2 -0
  22. data/lib/valkyrie/persistence/fedora/list_node.rb +46 -49
  23. data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +7 -3
  24. data/lib/valkyrie/persistence/fedora/ordered_list.rb +90 -90
  25. data/lib/valkyrie/persistence/fedora/ordered_reader.rb +5 -5
  26. data/lib/valkyrie/persistence/fedora/permissive_schema.rb +3 -3
  27. data/lib/valkyrie/persistence/fedora/persister.rb +82 -83
  28. data/lib/valkyrie/persistence/fedora/persister/model_converter.rb +15 -15
  29. data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +38 -18
  30. data/lib/valkyrie/persistence/fedora/query_service.rb +55 -54
  31. data/lib/valkyrie/persistence/memory/persister.rb +33 -33
  32. data/lib/valkyrie/persistence/memory/query_service.rb +52 -34
  33. data/lib/valkyrie/persistence/postgres/orm_converter.rb +52 -52
  34. data/lib/valkyrie/persistence/postgres/query_service.rb +86 -33
  35. data/lib/valkyrie/persistence/postgres/resource_converter.rb +1 -1
  36. data/lib/valkyrie/persistence/shared/json_value_mapper.rb +1 -1
  37. data/lib/valkyrie/persistence/solr/model_converter.rb +337 -337
  38. data/lib/valkyrie/persistence/solr/orm_converter.rb +3 -3
  39. data/lib/valkyrie/persistence/solr/persister.rb +4 -17
  40. data/lib/valkyrie/persistence/solr/queries/find_all_query.rb +6 -0
  41. data/lib/valkyrie/persistence/solr/queries/find_by_alternate_identifier_query.rb +1 -1
  42. data/lib/valkyrie/persistence/solr/queries/find_by_id_query.rb +1 -1
  43. data/lib/valkyrie/persistence/solr/queries/find_members_query.rb +1 -1
  44. data/lib/valkyrie/persistence/solr/query_service.rb +42 -53
  45. data/lib/valkyrie/persistence/solr/repository.rb +2 -1
  46. data/lib/valkyrie/rdf_patches.rb +2 -2
  47. data/lib/valkyrie/resource.rb +36 -5
  48. data/lib/valkyrie/specs/shared_specs/change_set.rb +1 -1
  49. data/lib/valkyrie/specs/shared_specs/persister.rb +13 -5
  50. data/lib/valkyrie/specs/shared_specs/queries.rb +112 -9
  51. data/lib/valkyrie/specs/shared_specs/resource.rb +1 -1
  52. data/lib/valkyrie/storage/fedora.rb +18 -18
  53. data/lib/valkyrie/storage_adapter.rb +16 -13
  54. data/lib/valkyrie/types.rb +3 -1
  55. data/lib/valkyrie/version.rb +1 -1
  56. data/lib/valkyrie/vocab/pcdm_use.rb +12 -0
  57. data/solr/config/solrconfig.xml +0 -10
  58. data/tasks/dev.rake +14 -51
  59. data/valkyrie.gemspec +4 -4
  60. metadata +38 -35
  61. data/.docker-stack/valkyrie-development/docker-compose.yml +0 -53
  62. data/.docker-stack/valkyrie-test/docker-compose.yml +0 -53
  63. data/db/seeds.rb +0 -8
  64. data/tasks/docker.rake +0 -31
@@ -325,21 +325,21 @@ module Valkyrie::Persistence::Fedora
325
325
  class MappedFedoraValue < ::Valkyrie::ValueMapper
326
326
  private
327
327
 
328
- # Map a default Ruby data type
329
- # (This maps the existing Property to a FedoraValue first)
330
- # @param [Object] converted_value
331
- # @return [Valkyrie::Persistence::Fedora::Persister::ModelConverter::Property]
332
- def map_value(converted_value:)
333
- calling_mapper.for(
334
- Property.new(
335
- value.subject,
336
- value.key,
337
- converted_value,
338
- value.adapter,
339
- value.resource
340
- )
341
- ).result
342
- end
328
+ # Map a default Ruby data type
329
+ # (This maps the existing Property to a FedoraValue first)
330
+ # @param [Object] converted_value
331
+ # @return [Valkyrie::Persistence::Fedora::Persister::ModelConverter::Property]
332
+ def map_value(converted_value:)
333
+ calling_mapper.for(
334
+ Property.new(
335
+ value.subject,
336
+ value.key,
337
+ converted_value,
338
+ value.adapter,
339
+ value.resource
340
+ )
341
+ ).result
342
+ end
343
343
  end
344
344
 
345
345
  # Class mapping Property objects for Valkyrie IDs using typed RDF literals
@@ -97,11 +97,9 @@ module Valkyrie::Persistence::Fedora
97
97
  end
98
98
  end
99
99
 
100
- # Class for handling cases where blacklisted values should not be mapped
101
- class BlacklistedValue < ::Valkyrie::ValueMapper
102
- FedoraValue.register(self)
103
-
104
- # Determines whether or not the value has a blacklisted namespace for the RDF statement object
100
+ # Class for handling cases where deny listed values should not be mapped
101
+ class DenylistedValue < ::Valkyrie::ValueMapper
102
+ # Determines whether or not the value has a denied namespace for the RDF statement object
105
103
  # (i. e. avoid attempting to map any RDF statements making assertions about LDP containers or resource internal to Fedora)
106
104
  # @param [Property] value
107
105
  # @return [Boolean]
@@ -109,12 +107,20 @@ module Valkyrie::Persistence::Fedora
109
107
  value.statement.object.to_s.start_with?("http://www.w3.org/ns/ldp", "http://fedora.info")
110
108
  end
111
109
 
112
- # Provide the NullApplicator Class for any Property in a blacklisted namespace
110
+ # Provide the NullApplicator Class for any Property in a deny listed namespace
113
111
  def result
114
112
  NullApplicator
115
113
  end
116
114
  end
117
115
 
116
+ # @deprecated
117
+ # Class for handling cases where deny listed values should not be mapped
118
+ # @see DenylistedValue
119
+ class BlacklistedValue < DenylistedValue
120
+ FedoraValue.register(self)
121
+ warn "[DEPRECATION] Samvera is deprecating '#{self}' in 3.0.0. Use #{DenylistedValue} instead."
122
+ end
123
+
118
124
  # Class for handling cases where the RDF subject of a Property references a separate resource using a hash URI
119
125
  class DifferentSubject < ::Valkyrie::ValueMapper
120
126
  FedoraValue.register(self)
@@ -318,7 +324,7 @@ module Valkyrie::Persistence::Fedora
318
324
  # Casts the value of the RDF literal into an Applicator for DateTime values
319
325
  # @return [Applicator]
320
326
  def result
321
- value.statement.object = ::DateTime.iso8601(value.statement.object.to_s).utc
327
+ value.statement.object = ::DateTime.iso8601(value.statement.object.to_s).new_offset(0)
322
328
  calling_mapper.for(Property.new(statement: value.statement, scope: value.scope, adapter: value.adapter)).result
323
329
  end
324
330
  end
@@ -394,7 +400,7 @@ module Valkyrie::Persistence::Fedora
394
400
  # Casts the value of the RDF literal into an Applicator for DateTime values
395
401
  # @return [Applicator]
396
402
  def result
397
- value.statement.object = Time.parse(value.statement.object.to_s).utc
403
+ value.statement.object = DateTime.parse(value.statement.object.to_s).new_offset(0)
398
404
  calling_mapper.for(Property.new(statement: value.statement, scope: value.scope, adapter: value.adapter)).result
399
405
  end
400
406
  end
@@ -522,7 +528,7 @@ module Valkyrie::Persistence::Fedora
522
528
  # @param [Hash] hsh a new or existing Hash of attribute for Valkyrie resource attributes
523
529
  # @return [Hash]
524
530
  def apply_to(hsh)
525
- return if blacklist?(key)
531
+ return if deny?(key)
526
532
  hsh[key.to_sym] = if hsh.key?(key.to_sym)
527
533
  Array.wrap(hsh[key.to_sym]) + cast_array(values)
528
534
  else
@@ -541,13 +547,23 @@ module Valkyrie::Persistence::Fedora
541
547
  key
542
548
  end
543
549
 
544
- # Determines whether or not a key is blacklisted for mapping
550
+ # @deprecated
551
+ # Determines whether or not a key is on the deny list for mapping
545
552
  # (For example <http://fedora.info/definitions> assertions are not mapped to Valkyrie attributes)
546
553
  # @param [Symbol] key
547
554
  # @return [Boolean]
548
555
  def blacklist?(key)
549
- blacklist.each do |blacklist_item|
550
- return true if key.start_with?(blacklist_item)
556
+ warn "[DEPRECATION] Samvera is deprecating '#{self.class}#blacklist?' in 3.0.0. Use #{self.class}#deny? instead."
557
+ deny?(key)
558
+ end
559
+
560
+ # Determines whether or not a key is on the deny list for mapping
561
+ # (For example <http://fedora.info/definitions> assertions are not mapped to Valkyrie attributes)
562
+ # @param [Symbol] key
563
+ # @return [Boolean]
564
+ def deny?(key)
565
+ denylist.each do |denylist_item|
566
+ return true if key.start_with?(denylist_item)
551
567
  end
552
568
  false
553
569
  end
@@ -556,16 +572,20 @@ module Valkyrie::Persistence::Fedora
556
572
  # @param [Object] values
557
573
  # @return [Array<Object>]
558
574
  def cast_array(values)
559
- if values.is_a?(Time)
560
- [values]
561
- else
562
- Array(values)
563
- end
575
+ Array(values)
564
576
  end
565
577
 
566
- # Retrieve a list of blacklisted URIs for predicates
578
+ # @deprecated
579
+ # Retrieve a list of denied URIs for predicates
567
580
  # @return [Array<String>]
568
581
  def blacklist
582
+ warn "[DEPRECATION] Samvera is deprecating '#{self.class}#blacklist' in 3.0.0. Use #{self.class}#denylist instead."
583
+ denylist
584
+ end
585
+
586
+ # Retrieve a list of denied URIs for predicates
587
+ # @return [Array<String>]
588
+ def denylist
569
589
  [
570
590
  "http://fedora.info/definitions",
571
591
  "http://www.iana.org/assignments/relation/last"
@@ -31,11 +31,9 @@ module Valkyrie::Persistence::Fedora
31
31
  def find_many_by_ids(ids:)
32
32
  ids = ids.uniq
33
33
  ids.map do |id|
34
- begin
35
- find_by(id: id)
36
- rescue ::Valkyrie::Persistence::ObjectNotFoundError
37
- nil
38
- end
34
+ find_by(id: id)
35
+ rescue ::Valkyrie::Persistence::ObjectNotFoundError
36
+ nil
39
37
  end.reject(&:nil?)
40
38
  end
41
39
 
@@ -54,7 +52,7 @@ module Valkyrie::Persistence::Fedora
54
52
  # @return [Array<RDF::URI>]
55
53
  def include_uris
56
54
  [
57
- adapter.fedora_version == 5 ? "http://fedora.info/definitions/fcrepo#PreferInboundReferences" : ::RDF::Vocab::Fcrepo4.InboundReferences
55
+ [5, 6].include?(adapter.fedora_version) ? "http://fedora.info/definitions/fcrepo#PreferInboundReferences" : ::RDF::Vocab::Fcrepo4.InboundReferences
58
56
  ]
59
57
  end
60
58
 
@@ -86,11 +84,18 @@ module Valkyrie::Persistence::Fedora
86
84
  end
87
85
  end
88
86
 
87
+ # (see Valkyrie::Persistence::Memory::QueryService#count_all_of_model)
88
+ def count_all_of_model(model:)
89
+ find_all_of_model(model: model).count
90
+ end
91
+
89
92
  # (see Valkyrie::Persistence::Memory::QueryService#find_references_by)
90
- def find_references_by(resource:, property:)
91
- (resource[property] || []).select { |x| x.is_a?(Valkyrie::ID) }.lazy.map do |id|
93
+ def find_references_by(resource:, property:, model: nil)
94
+ objects = (resource[property] || []).select { |x| x.is_a?(Valkyrie::ID) }.lazy.map do |id|
92
95
  find_by(id: id)
93
96
  end
97
+ return objects unless model
98
+ objects.select { |obj| obj.is_a?(model) }
94
99
  end
95
100
 
96
101
  # Retrieves the RDF graph for the LDP container for a resource
@@ -111,15 +116,16 @@ module Valkyrie::Persistence::Fedora
111
116
  # Find all resources referencing a given resource (e. g. parents)
112
117
  # *This is done by iterating through the ID of each resource referencing the resource in the query, and requesting each resource over the HTTP*
113
118
  # *Also, an initial request is made to find the URIs of the resources referencing the resource in the query*
114
- def find_inverse_references_by(resource: nil, id: nil, property:)
119
+ def find_inverse_references_by(resource: nil, id: nil, property:, model: nil)
115
120
  raise ArgumentError, "Provide resource or id" unless resource || id
116
121
  ensure_persisted(resource) if resource
117
122
  resource ||= find_by(id: id)
118
- if ordered_property?(resource: resource, property: property)
119
- find_inverse_references_by_ordered(resource: resource, property: property)
120
- else
121
- find_inverse_references_by_unordered(resource: resource, property: property)
122
- end
123
+ ids = find_inverse_reference_ids_by_unordered(resource: resource, property: property).uniq
124
+ objects_from_unordered = ids.lazy.map { |ref_id| find_by(id: ref_id) }
125
+ objects_from_ordered = find_inverse_references_by_ordered(resource: resource, property: property, ignore_ids: ids)
126
+ objects = [objects_from_unordered, objects_from_ordered].lazy.flat_map(&:lazy)
127
+ return objects unless model
128
+ objects.select { |obj| obj.is_a?(model) }
123
129
  end
124
130
 
125
131
  # (see Valkyrie::Persistence::Memory::QueryService#custom_queries)
@@ -129,49 +135,44 @@ module Valkyrie::Persistence::Fedora
129
135
 
130
136
  private
131
137
 
132
- def find_inverse_references_by_unordered(resource:, property:)
133
- content = content_with_inbound(id: resource.id)
134
- property_uri = adapter.schema.predicate_for(property: property, resource: nil)
135
- ids = content.graph.query([nil, property_uri, adapter.id_to_uri(resource.id)]).map(&:subject).map { |x| x.to_s.gsub(/#.*/, '') }.map { |x| adapter.uri_to_id(x) }
136
- ids.uniq!
137
- ids.lazy.map { |id| find_by(id: id) }
138
- end
139
-
140
- def find_inverse_references_by_ordered(resource:, property:)
141
- content = content_with_inbound(id: resource.id)
142
- ids = content.graph.query([nil, ::RDF::Vocab::ORE.proxyFor, adapter.id_to_uri(resource.id)]).map(&:subject).map { |x| x.to_s.gsub(/#.*/, '') }.map { |x| adapter.uri_to_id(x) }
143
- ids.uniq!
144
- ids.lazy.map { |id| find_by(id: id) }.select { |o| o[property].include?(resource.id) }
145
- end
138
+ def find_inverse_reference_ids_by_unordered(resource:, property:)
139
+ content = content_with_inbound(id: resource.id)
140
+ property_uri = adapter.schema.predicate_for(property: property, resource: nil)
141
+ content.graph.query([nil, property_uri, adapter.id_to_uri(resource.id)]).map(&:subject).map { |x| x.to_s.gsub(/#.*/, '') }.map { |x| adapter.uri_to_id(x) }
142
+ end
146
143
 
147
- # Ensures that an object is (or can be cast into a) Valkyrie::ID
148
- # @return [Valkyrie::ID]
149
- # @raise [ArgumentError]
150
- def validate_id(id)
151
- id = Valkyrie::ID.new(id.to_s) if id.is_a?(String)
152
- raise ArgumentError, 'id must be a Valkyrie::ID' unless id.is_a? Valkyrie::ID
153
- end
144
+ def find_inverse_references_by_ordered(resource:, property:, ignore_ids: [])
145
+ content = content_with_inbound(id: resource.id)
146
+ ids = content.graph.query([nil, ::RDF::Vocab::ORE.proxyFor, adapter.id_to_uri(resource.id)]).map(&:subject).map { |x| x.to_s.gsub(/#.*/, '') }.map { |x| adapter.uri_to_id(x) }
147
+ ids.uniq!
148
+ ids.delete_if { |id| ignore_ids.include? id }
149
+ ids.lazy.map { |id| find_by(id: id) }.select { |o| o[property].include?(resource.id) }
150
+ end
154
151
 
155
- # Resolve a URI for an LDP resource in Fedora and construct a Valkyrie::Resource
156
- # @param uri [RDF::URI]
157
- # @return [Valkyrie::Resource]
158
- # @raise [Valkyrie::Persistence::ObjectNotFoundError]
159
- def resource_from_uri(uri)
160
- resource = Ldp::Resource.for(connection, uri, connection.get(uri))
161
- resource_factory.to_resource(object: resource)
162
- rescue ::Ldp::Gone, ::Ldp::NotFound
163
- raise ::Valkyrie::Persistence::ObjectNotFoundError
164
- end
152
+ # Ensures that an object is (or can be cast into a) Valkyrie::ID
153
+ # @return [Valkyrie::ID]
154
+ # @raise [ArgumentError]
155
+ def validate_id(id)
156
+ id = Valkyrie::ID.new(id.to_s) if id.is_a?(String)
157
+ raise ArgumentError, 'id must be a Valkyrie::ID' unless id.is_a? Valkyrie::ID
158
+ end
165
159
 
166
- # Ensures that a Valkyrie::Resource has been persisted
167
- # @param resource [Valkyrie::Resource]
168
- # @raise [ArgumentError]
169
- def ensure_persisted(resource)
170
- raise ArgumentError, 'resource is not saved' unless resource.persisted?
171
- end
160
+ # Resolve a URI for an LDP resource in Fedora and construct a Valkyrie::Resource
161
+ # @param uri [RDF::URI]
162
+ # @return [Valkyrie::Resource]
163
+ # @raise [Valkyrie::Persistence::ObjectNotFoundError]
164
+ def resource_from_uri(uri)
165
+ resource = Ldp::Resource.for(connection, uri, connection.get(uri))
166
+ resource_factory.to_resource(object: resource)
167
+ rescue ::Ldp::Gone, ::Ldp::NotFound
168
+ raise ::Valkyrie::Persistence::ObjectNotFoundError
169
+ end
172
170
 
173
- def ordered_property?(resource:, property:)
174
- resource.ordered_attribute?(property)
175
- end
171
+ # Ensures that a Valkyrie::Resource has been persisted
172
+ # @param resource [Valkyrie::Resource]
173
+ # @raise [ArgumentError]
174
+ def ensure_persisted(resource)
175
+ raise ArgumentError, 'resource is not saved' unless resource.persisted?
176
+ end
176
177
  end
177
178
  end
@@ -62,46 +62,46 @@ module Valkyrie::Persistence::Memory
62
62
 
63
63
  private
64
64
 
65
- def generate_id(resource)
66
- resource.new(id: SecureRandom.uuid)
67
- end
65
+ def generate_id(resource)
66
+ resource.new(id: SecureRandom.uuid)
67
+ end
68
68
 
69
- # Convert all dates to DateTime in the UTC time zone for consistency.
70
- def normalize_dates!(resource)
71
- resource.attributes.each { |k, v| resource.send("#{k}=", normalize_date_values(v)) }
72
- end
69
+ # Convert all dates to DateTime in the UTC time zone for consistency.
70
+ def normalize_dates!(resource)
71
+ resource.attributes.each { |k, v| resource.send("#{k}=", normalize_date_values(v)) }
72
+ end
73
73
 
74
- def normalize_date_values(v)
75
- return v.map { |val| normalize_date_value(val) } if v.is_a?(Array)
76
- normalize_date_value(v)
77
- end
74
+ def normalize_date_values(v)
75
+ return v.map { |val| normalize_date_value(val) } if v.is_a?(Array)
76
+ normalize_date_value(v)
77
+ end
78
78
 
79
- def normalize_date_value(value)
80
- return value.utc if value.is_a?(DateTime)
81
- return value.to_datetime.utc if value.is_a?(Time)
82
- value
83
- end
79
+ def normalize_date_value(value)
80
+ return value.new_offset(0) if value.is_a?(DateTime)
81
+ return value.to_datetime.new_offset(0) if value.is_a?(Time)
82
+ value
83
+ end
84
84
 
85
- # Create a new lock token based on the current timestamp.
86
- def generate_lock_token(resource)
87
- return unless resource.optimistic_locking_enabled?
88
- token = Valkyrie::Persistence::OptimisticLockToken.new(adapter_id: adapter.id, token: Time.now.to_r)
89
- resource.set_value(Valkyrie::Persistence::Attributes::OPTIMISTIC_LOCK, token)
90
- end
85
+ # Create a new lock token based on the current timestamp.
86
+ def generate_lock_token(resource)
87
+ return unless resource.optimistic_locking_enabled?
88
+ token = Valkyrie::Persistence::OptimisticLockToken.new(adapter_id: adapter.id, token: Time.now.to_r)
89
+ resource.set_value(Valkyrie::Persistence::Attributes::OPTIMISTIC_LOCK, token)
90
+ end
91
91
 
92
- # Check whether a resource is current.
93
- def valid_lock?(resource)
94
- return true unless resource.optimistic_locking_enabled?
92
+ # Check whether a resource is current.
93
+ def valid_lock?(resource)
94
+ return true unless resource.optimistic_locking_enabled?
95
95
 
96
- cached_resource = cache[resource.id]
97
- return true if cached_resource.blank?
96
+ cached_resource = cache[resource.id]
97
+ return true if cached_resource.blank?
98
98
 
99
- resource_lock_tokens = resource[Valkyrie::Persistence::Attributes::OPTIMISTIC_LOCK]
100
- resource_value = resource_lock_tokens.find { |lock_token| lock_token.adapter_id == adapter.id }
101
- return true if resource_value.blank?
99
+ resource_lock_tokens = resource[Valkyrie::Persistence::Attributes::OPTIMISTIC_LOCK]
100
+ resource_value = resource_lock_tokens.find { |lock_token| lock_token.adapter_id == adapter.id }
101
+ return true if resource_value.blank?
102
102
 
103
- cached_value = cached_resource[Valkyrie::Persistence::Attributes::OPTIMISTIC_LOCK].first
104
- cached_value == resource_value
105
- end
103
+ cached_value = cached_resource[Valkyrie::Persistence::Attributes::OPTIMISTIC_LOCK].first
104
+ cached_value == resource_value
105
+ end
106
106
  end
107
107
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  module Valkyrie::Persistence::Memory
3
+ # Query Service for the memory metadata adapter.
4
+ # @see Valkyrie::Persistence::Memory
5
+ # @note Documentation for Query Services in general is maintained here.
3
6
  class QueryService
4
- # Query Service for the memory metadata adapter.
5
- # @see Valkyrie::Persistence::Memory
6
- # @note Documentation for Query Services in general is maintained here.
7
7
  attr_reader :adapter, :query_handlers
8
8
  delegate :cache, to: :adapter
9
9
 
@@ -27,7 +27,9 @@ module Valkyrie::Persistence::Memory
27
27
  cache[id] || raise(::Valkyrie::Persistence::ObjectNotFoundError)
28
28
  end
29
29
 
30
- # Get a single resource by `alternate_identifier`.
30
+ # Get a single resource by `alternate_identifier`. Alternate identifiers are identifiers (like NOIDs,
31
+ # DOIs, ARKs, etc.) that are not the system-generated ID, but might be used to identify a resource in an
32
+ # application (e.g., to make shorter URLs).
31
33
  # @param alternate_identifier [Valkyrie::ID] The alternate identifier to query for.
32
34
  # @raise [Valkyrie::Persistence::ObjectNotFoundError] Raised when the alternate identifier
33
35
  # isn't in the persistence backend.
@@ -49,11 +51,9 @@ module Valkyrie::Persistence::Memory
49
51
  def find_many_by_ids(ids:)
50
52
  ids = ids.uniq
51
53
  ids.map do |id|
52
- begin
53
- find_by(id: id)
54
- rescue ::Valkyrie::Persistence::ObjectNotFoundError
55
- nil
56
- end
54
+ find_by(id: id)
55
+ rescue ::Valkyrie::Persistence::ObjectNotFoundError
56
+ nil
57
57
  end.reject(&:nil?)
58
58
  end
59
59
 
@@ -73,9 +73,17 @@ module Valkyrie::Persistence::Memory
73
73
  end
74
74
  end
75
75
 
76
+ # Count all objects of a given model.
77
+ # @param model [Class] Class to query for.
78
+ # @return integer. Count objects in the persistence backend
79
+ # with the given class.
80
+ def count_all_of_model(model:)
81
+ cache.values.count { |obj| obj.is_a?(model) }
82
+ end
83
+
76
84
  # Get all members of a given resource.
77
85
  # @param resource [Valkyrie::Resource] Model whose members are being searched for.
78
- # @param model [Class] Class to query for. (optional)
86
+ # @param model [Class] Filter results to include only instances of this model. (optional)
79
87
  # @return [Array<Valkyrie::Resource>] child objects of type `model` referenced by
80
88
  # `resource`'s `member_ids` method. Returned in order.
81
89
  def find_members(resource:, model: nil)
@@ -90,36 +98,41 @@ module Valkyrie::Persistence::Memory
90
98
  # @param resource [Valkyrie::Resource] Model whose property is being searched.
91
99
  # @param property [Symbol] Property which, on the `resource`, contains {Valkyrie::ID}s which are
92
100
  # to be de-referenced.
101
+ # @param model [Class] Filter results to include only instances of this model. (optional)
93
102
  # @return [Array<Valkyrie::Resource>] All objects which are referenced by the
94
103
  # `property` property on `resource`. Not necessarily in order.
95
- def find_references_by(resource:, property:)
104
+ def find_references_by(resource:, property:, model: nil)
96
105
  refs = Array.wrap(resource[property]).map do |id|
97
- begin
98
- find_by(id: id)
99
- rescue ::Valkyrie::Persistence::ObjectNotFoundError
100
- nil
101
- end
106
+ find_by(id: id)
107
+ rescue ::Valkyrie::Persistence::ObjectNotFoundError
108
+ nil
102
109
  end.reject(&:nil?)
103
110
  refs.uniq! unless ordered_property?(resource: resource, property: property)
104
- refs
111
+ return refs unless model
112
+ refs.select { |obj| obj.is_a?(model) }
105
113
  end
106
114
 
107
115
  # Get all resources which link to a resource with a given property.
108
116
  # @param resource [Valkyrie::Resource] The resource which is being referenced by
109
- # other resources.
117
+ # other resources. Requires either resource or id parameter to be specified.
118
+ # @param id [Valkyrie::ID] ID of the resource which is being reference by other
119
+ # resources. Requires either resource or id parameter to be specified.
110
120
  # @param property [Symbol] The property which, on other resources, is
111
121
  # referencing the given `resource`
122
+ # @param model [Class] Filter results to include only instances of this model. (optional)
112
123
  # @raise [ArgumentError] Raised when the ID is not in the persistence backend.
113
124
  # @return [Array<Valkyrie::Resource>] All resources in the persistence backend
114
125
  # which have the ID of the given `resource` in their `property` property. Not
115
126
  # in order.
116
- def find_inverse_references_by(resource: nil, id: nil, property:)
127
+ def find_inverse_references_by(resource: nil, id: nil, property:, model: nil)
117
128
  raise ArgumentError, "Provide resource or id" unless resource || id
118
129
  ensure_persisted(resource) if resource
119
130
  id ||= resource.id
120
- find_all.select do |obj|
131
+ result = find_all.select do |obj|
121
132
  Array.wrap(obj[property]).include?(id)
122
133
  end
134
+ return result unless model
135
+ result.select { |obj| obj.is_a?(model) }
123
136
  end
124
137
 
125
138
  # Find all parents of a given resource.
@@ -142,22 +155,27 @@ module Valkyrie::Persistence::Memory
142
155
 
143
156
  private
144
157
 
145
- # @return [Array<Valkyrie::ID>] a list of the identifiers of the member objects
146
- def member_ids(resource:)
147
- return [] unless resource.respond_to? :member_ids
148
- resource.member_ids || []
149
- end
158
+ # @return [Array<Valkyrie::ID>] a list of the identifiers of the member objects
159
+ def member_ids(resource:)
160
+ return [] unless resource.respond_to? :member_ids
161
+ resource.member_ids || []
162
+ end
150
163
 
151
- def validate_id(id)
152
- raise ArgumentError, 'id must be a Valkyrie::ID' unless id.is_a? Valkyrie::ID
153
- end
164
+ # Determine whether or not a value is a Valkyrie ID
165
+ # @param [Object] id
166
+ # @return [Boolean]
167
+ def validate_id(id)
168
+ raise ArgumentError, 'id must be a Valkyrie::ID' unless id.is_a? Valkyrie::ID
169
+ end
154
170
 
155
- def ensure_persisted(resource)
156
- raise ArgumentError, 'resource is not saved' unless resource.persisted?
157
- end
171
+ # Ensure that a given Valkyrie Resource has been persisted
172
+ # @param [Valkyrie::Resource] resource
173
+ def ensure_persisted(resource)
174
+ raise ArgumentError, 'resource is not saved' unless resource.persisted?
175
+ end
158
176
 
159
- def ordered_property?(resource:, property:)
160
- resource.ordered_attribute?(property)
161
- end
177
+ def ordered_property?(resource:, property:)
178
+ resource.ordered_attribute?(property)
179
+ end
162
180
  end
163
181
  end