valkyrie 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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