valkyrie 0.0.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -3
- data/.rubocop.yml +28 -0
- data/Gemfile +6 -1
- data/README.md +145 -10
- data/Rakefile +59 -1
- data/bin/console +1 -1
- data/config/valkyrie.yml +8 -0
- data/db/config.yml +17 -0
- data/db/migrate/20160111215816_enable_uuid_extension.rb +6 -0
- data/db/migrate/20161007101725_create_orm_resources.rb +10 -0
- data/db/migrate/20170124135846_add_model_type_to_orm_resources.rb +6 -0
- data/db/migrate/20170531004548_change_model_type_to_internal_model.rb +6 -0
- data/db/schema.rb +65 -0
- data/db/seeds.rb +8 -0
- data/lib/config/database_connection.rb +15 -0
- data/lib/generators/valkyrie/resource_generator.rb +27 -0
- data/lib/generators/valkyrie/templates/resource.rb.erb +9 -0
- data/lib/generators/valkyrie/templates/resource_spec.rb.erb +13 -0
- data/lib/valkyrie.rb +76 -1
- data/lib/valkyrie/adapter_container.rb +12 -0
- data/lib/valkyrie/change_set.rb +84 -0
- data/lib/valkyrie/decorators/decorator_list.rb +15 -0
- data/lib/valkyrie/decorators/decorator_with_arguments.rb +14 -0
- data/lib/valkyrie/derivative_service.rb +42 -0
- data/lib/valkyrie/engine.rb +10 -0
- data/lib/valkyrie/file_characterization_service.rb +42 -0
- data/lib/valkyrie/id.rb +32 -0
- data/lib/valkyrie/indexers/access_controls_indexer.rb +19 -0
- data/lib/valkyrie/local_file_service.rb +11 -0
- data/lib/valkyrie/metadata_adapter.rb +22 -0
- data/lib/valkyrie/persist_derivatives.rb +29 -0
- data/lib/valkyrie/persistence.rb +14 -0
- data/lib/valkyrie/persistence/buffered_persister.rb +28 -0
- data/lib/valkyrie/persistence/composite_persister.rb +29 -0
- data/lib/valkyrie/persistence/delete_tracking_buffer.rb +21 -0
- data/lib/valkyrie/persistence/fedora.rb +11 -0
- data/lib/valkyrie/persistence/fedora/list_node.rb +88 -0
- data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +45 -0
- data/lib/valkyrie/persistence/fedora/ordered_list.rb +146 -0
- data/lib/valkyrie/persistence/fedora/ordered_reader.rb +28 -0
- data/lib/valkyrie/persistence/fedora/persister.rb +47 -0
- data/lib/valkyrie/persistence/fedora/persister/model_converter.rb +199 -0
- data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +338 -0
- data/lib/valkyrie/persistence/fedora/persister/resource_factory.rb +21 -0
- data/lib/valkyrie/persistence/fedora/query_service.rb +80 -0
- data/lib/valkyrie/persistence/memory.rb +8 -0
- data/lib/valkyrie/persistence/memory/metadata_adapter.rb +22 -0
- data/lib/valkyrie/persistence/memory/persister.rb +58 -0
- data/lib/valkyrie/persistence/memory/query_service.rb +86 -0
- data/lib/valkyrie/persistence/postgres.rb +6 -0
- data/lib/valkyrie/persistence/postgres/metadata_adapter.rb +20 -0
- data/lib/valkyrie/persistence/postgres/orm.rb +9 -0
- data/lib/valkyrie/persistence/postgres/orm/resource.rb +7 -0
- data/lib/valkyrie/persistence/postgres/orm_converter.rb +118 -0
- data/lib/valkyrie/persistence/postgres/persister.rb +33 -0
- data/lib/valkyrie/persistence/postgres/queries.rb +8 -0
- data/lib/valkyrie/persistence/postgres/queries/find_inverse_references_query.rb +31 -0
- data/lib/valkyrie/persistence/postgres/queries/find_members_query.rb +33 -0
- data/lib/valkyrie/persistence/postgres/queries/find_references_query.rb +33 -0
- data/lib/valkyrie/persistence/postgres/query_service.rb +53 -0
- data/lib/valkyrie/persistence/postgres/resource_converter.rb +18 -0
- data/lib/valkyrie/persistence/postgres/resource_factory.rb +30 -0
- data/lib/valkyrie/persistence/solr.rb +6 -0
- data/lib/valkyrie/persistence/solr/metadata_adapter.rb +42 -0
- data/lib/valkyrie/persistence/solr/model_converter.rb +270 -0
- data/lib/valkyrie/persistence/solr/orm_converter.rb +252 -0
- data/lib/valkyrie/persistence/solr/persister.rb +32 -0
- data/lib/valkyrie/persistence/solr/queries.rb +11 -0
- data/lib/valkyrie/persistence/solr/queries/default_paginator.rb +16 -0
- data/lib/valkyrie/persistence/solr/queries/find_all_query.rb +33 -0
- data/lib/valkyrie/persistence/solr/queries/find_by_id_query.rb +24 -0
- data/lib/valkyrie/persistence/solr/queries/find_inverse_references_query.rb +30 -0
- data/lib/valkyrie/persistence/solr/queries/find_members_query.rb +43 -0
- data/lib/valkyrie/persistence/solr/queries/find_references_query.rb +34 -0
- data/lib/valkyrie/persistence/solr/query_service.rb +48 -0
- data/lib/valkyrie/persistence/solr/repository.rb +36 -0
- data/lib/valkyrie/persistence/solr/resource_factory.rb +24 -0
- data/lib/valkyrie/rdf_patches.rb +17 -0
- data/lib/valkyrie/resource.rb +106 -0
- data/lib/valkyrie/resource/access_controls.rb +13 -0
- data/lib/valkyrie/specs/shared_specs.rb +10 -0
- data/lib/valkyrie/specs/shared_specs/change_set_persister.rb +60 -0
- data/lib/valkyrie/specs/shared_specs/derivative_service.rb +30 -0
- data/lib/valkyrie/specs/shared_specs/file.rb +12 -0
- data/lib/valkyrie/specs/shared_specs/file_characterization_service.rb +33 -0
- data/lib/valkyrie/specs/shared_specs/metadata_adapter.rb +10 -0
- data/lib/valkyrie/specs/shared_specs/persister.rb +154 -0
- data/lib/valkyrie/specs/shared_specs/queries.rb +128 -0
- data/lib/valkyrie/specs/shared_specs/resource.rb +71 -0
- data/lib/valkyrie/specs/shared_specs/storage_adapter.rb +44 -0
- data/lib/valkyrie/storage.rb +8 -0
- data/lib/valkyrie/storage/disk.rb +55 -0
- data/lib/valkyrie/storage/fedora.rb +71 -0
- data/lib/valkyrie/storage/memory.rb +31 -0
- data/lib/valkyrie/storage_adapter.rb +100 -0
- data/lib/valkyrie/types.rb +34 -0
- data/lib/valkyrie/value_mapper.rb +67 -0
- data/lib/valkyrie/version.rb +2 -1
- data/lib/valkyrie/vocab/pcdm_use.rb +73 -0
- data/valkyrie.gemspec +33 -7
- metadata +462 -7
- data/.travis.yml +0 -5
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'valkyrie/persistence/postgres/orm'
|
|
3
|
+
require 'valkyrie/persistence/postgres/resource_factory'
|
|
4
|
+
module Valkyrie::Persistence::Postgres
|
|
5
|
+
class Persister
|
|
6
|
+
attr_reader :adapter
|
|
7
|
+
delegate :resource_factory, to: :adapter
|
|
8
|
+
def initialize(adapter:)
|
|
9
|
+
@adapter = adapter
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# (see Valkyrie::Persistence::Memory::Persister#save)
|
|
13
|
+
def save(resource:)
|
|
14
|
+
orm_object = resource_factory.from_resource(resource: resource)
|
|
15
|
+
orm_object.save!
|
|
16
|
+
resource_factory.to_resource(object: orm_object)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# (see Valkyrie::Persistence::Memory::Persister#save_all)
|
|
20
|
+
def save_all(resources:)
|
|
21
|
+
resources.map do |resource|
|
|
22
|
+
save(resource: resource)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# (see Valkyrie::Persistence::Memory::Persister#delete)
|
|
27
|
+
def delete(resource:)
|
|
28
|
+
orm_object = resource_factory.from_resource(resource: resource)
|
|
29
|
+
orm_object.delete
|
|
30
|
+
resource
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'valkyrie/persistence/postgres/queries/find_inverse_references_query'
|
|
3
|
+
require 'valkyrie/persistence/postgres/queries/find_members_query'
|
|
4
|
+
require 'valkyrie/persistence/postgres/queries/find_references_query'
|
|
5
|
+
module Valkyrie::Persistence::Postgres
|
|
6
|
+
module Queries
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Valkyrie::Persistence::Postgres::Queries
|
|
3
|
+
class FindInverseReferencesQuery
|
|
4
|
+
delegate :orm_class, to: :resource_factory
|
|
5
|
+
attr_reader :obj, :property, :resource_factory
|
|
6
|
+
def initialize(obj, property, resource_factory:)
|
|
7
|
+
@obj = obj
|
|
8
|
+
@property = property
|
|
9
|
+
@resource_factory = resource_factory
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
relation.lazy.map do |orm_object|
|
|
14
|
+
resource_factory.to_resource(object: orm_object)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def relation
|
|
21
|
+
orm_class.find_by_sql([query, property, "[{\"id\": \"#{obj.id}\"}]"])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def query
|
|
25
|
+
<<-SQL
|
|
26
|
+
SELECT * FROM orm_resources WHERE
|
|
27
|
+
metadata->? @> ?
|
|
28
|
+
SQL
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Valkyrie::Persistence::Postgres::Queries
|
|
3
|
+
class FindMembersQuery
|
|
4
|
+
attr_reader :obj, :resource_factory
|
|
5
|
+
delegate :orm_class, to: :resource_factory
|
|
6
|
+
def initialize(obj, resource_factory:)
|
|
7
|
+
@obj = obj
|
|
8
|
+
@resource_factory = resource_factory
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
return [] if obj.id.blank?
|
|
13
|
+
relation.lazy.map do |orm_object|
|
|
14
|
+
resource_factory.to_resource(object: orm_object)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def relation
|
|
21
|
+
orm_class.find_by_sql([query, obj.id.to_s])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def query
|
|
25
|
+
<<-SQL
|
|
26
|
+
SELECT member.* FROM orm_resources a,
|
|
27
|
+
jsonb_array_elements(a.metadata->'member_ids') WITH ORDINALITY AS b(member, member_pos)
|
|
28
|
+
JOIN orm_resources member ON (b.member->>'id')::uuid = member.id WHERE a.id = ?
|
|
29
|
+
ORDER BY b.member_pos
|
|
30
|
+
SQL
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Valkyrie::Persistence::Postgres::Queries
|
|
3
|
+
class FindReferencesQuery
|
|
4
|
+
delegate :orm_class, to: :resource_factory
|
|
5
|
+
attr_reader :obj, :property, :resource_factory
|
|
6
|
+
def initialize(obj, property, resource_factory:)
|
|
7
|
+
@obj = obj
|
|
8
|
+
@property = property
|
|
9
|
+
@resource_factory = resource_factory
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
return [] if obj.id.blank? || obj[property].blank?
|
|
14
|
+
relation.lazy.map do |orm_object|
|
|
15
|
+
resource_factory.to_resource(object: orm_object)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def relation
|
|
22
|
+
orm_class.find_by_sql([query, property, obj.id.to_s])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def query
|
|
26
|
+
<<-SQL
|
|
27
|
+
SELECT member.* FROM orm_resources a,
|
|
28
|
+
jsonb_array_elements(a.metadata->?) AS b(member)
|
|
29
|
+
JOIN orm_resources member ON (b.member->>'id')::uuid = member.id WHERE a.id = ?
|
|
30
|
+
SQL
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'valkyrie/persistence/postgres/queries'
|
|
3
|
+
module Valkyrie::Persistence::Postgres
|
|
4
|
+
class QueryService
|
|
5
|
+
attr_reader :adapter
|
|
6
|
+
delegate :resource_factory, to: :adapter
|
|
7
|
+
delegate :orm_class, to: :resource_factory
|
|
8
|
+
def initialize(adapter:)
|
|
9
|
+
@adapter = adapter
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# (see Valkyrie::Persistence::Memory::QueryService#find_all)
|
|
13
|
+
def find_all
|
|
14
|
+
orm_class.all.lazy.map do |orm_object|
|
|
15
|
+
resource_factory.to_resource(object: orm_object)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# (see Valkyrie::Persistence::Memory::QueryService#find_all_of_model)
|
|
20
|
+
def find_all_of_model(model:)
|
|
21
|
+
orm_class.where(internal_resource: model.to_s).lazy.map do |orm_object|
|
|
22
|
+
resource_factory.to_resource(object: orm_object)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# (see Valkyrie::Persistence::Memory::QueryService#find_by)
|
|
27
|
+
def find_by(id:)
|
|
28
|
+
resource_factory.to_resource(object: orm_class.find(id))
|
|
29
|
+
rescue ActiveRecord::RecordNotFound
|
|
30
|
+
raise Valkyrie::Persistence::ObjectNotFoundError
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# (see Valkyrie::Persistence::Memory::QueryService#find_members)
|
|
34
|
+
def find_members(resource:)
|
|
35
|
+
Valkyrie::Persistence::Postgres::Queries::FindMembersQuery.new(resource, resource_factory: resource_factory).run
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# (see Valkyrie::Persistence::Memory::QueryService#find_parents)
|
|
39
|
+
def find_parents(resource:)
|
|
40
|
+
find_inverse_references_by(resource: resource, property: :member_ids)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# (see Valkyrie::Persistence::Memory::QueryService#find_references_by)
|
|
44
|
+
def find_references_by(resource:, property:)
|
|
45
|
+
Valkyrie::Persistence::Postgres::Queries::FindReferencesQuery.new(resource, property, resource_factory: resource_factory).run
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# (see Valkyrie::Persistence::Memory::QueryService#find_inverse_references_by)
|
|
49
|
+
def find_inverse_references_by(resource:, property:)
|
|
50
|
+
Valkyrie::Persistence::Postgres::Queries::FindInverseReferencesQuery.new(resource, property, resource_factory: resource_factory).run
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Valkyrie::Persistence::Postgres
|
|
3
|
+
class ResourceConverter
|
|
4
|
+
delegate :orm_class, to: :resource_factory
|
|
5
|
+
attr_reader :resource, :resource_factory
|
|
6
|
+
def initialize(resource, resource_factory:)
|
|
7
|
+
@resource = resource
|
|
8
|
+
@resource_factory = resource_factory
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def convert!
|
|
12
|
+
orm_class.find_or_initialize_by(id: resource.id.to_s).tap do |orm_object|
|
|
13
|
+
orm_object.internal_resource = resource.internal_resource
|
|
14
|
+
orm_object.metadata.merge!(resource.attributes.except(:id, :internal_resource, :created_at, :updated_at))
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'valkyrie/persistence/postgres/orm_converter'
|
|
3
|
+
require 'valkyrie/persistence/postgres/resource_converter'
|
|
4
|
+
module Valkyrie::Persistence::Postgres
|
|
5
|
+
class ResourceFactory
|
|
6
|
+
class << self
|
|
7
|
+
# @param orm_object [Valkyrie::Persistence::Postgres::ORM::Resource] AR
|
|
8
|
+
# record to be converted.
|
|
9
|
+
# @return [Valkyrie::Resource] Model representation of the AR record.
|
|
10
|
+
def to_resource(object:)
|
|
11
|
+
::Valkyrie::Persistence::Postgres::ORMConverter.new(object).convert!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @param resource [Valkyrie::Resource] Model to be converted to ActiveRecord.
|
|
15
|
+
# @return [Valkyrie::Persistence::Postgres::ORM::Resource] ActiveRecord
|
|
16
|
+
# resource for the Valkyrie resource.
|
|
17
|
+
def from_resource(resource:)
|
|
18
|
+
::Valkyrie::Persistence::Postgres::ResourceConverter.new(resource, resource_factory: self).convert!
|
|
19
|
+
# ::Valkyrie::Persistence::Postgres::ORM::Resource.find_or_initialize_by(id: resource.id.to_s).tap do |orm_object|
|
|
20
|
+
# orm_object.internal_resource = resource.internal_resource
|
|
21
|
+
# orm_object.metadata.merge!(resource.attributes.except(:id, :internal_resource, :created_at, :updated_at))
|
|
22
|
+
# end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def orm_class
|
|
26
|
+
::Valkyrie::Persistence::Postgres::ORM::Resource
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'rsolr'
|
|
3
|
+
module Valkyrie::Persistence::Solr
|
|
4
|
+
require 'valkyrie/persistence/solr/persister'
|
|
5
|
+
require 'valkyrie/persistence/solr/query_service'
|
|
6
|
+
require 'valkyrie/persistence/solr/resource_factory'
|
|
7
|
+
class MetadataAdapter
|
|
8
|
+
attr_reader :connection, :resource_indexer
|
|
9
|
+
# @param connection [RSolr::Client] The RSolr connection to index to.
|
|
10
|
+
# @param resource_indexer [Class, #to_solr] An indexer which is able to
|
|
11
|
+
# receive a `resource` argument and then has an instance method `#to_solr`
|
|
12
|
+
def initialize(connection:, resource_indexer: NullIndexer)
|
|
13
|
+
@connection = connection
|
|
14
|
+
@resource_indexer = resource_indexer
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [Valkyrie::Persistence::Solr::Persister] The solr persister.
|
|
18
|
+
def persister
|
|
19
|
+
Valkyrie::Persistence::Solr::Persister.new(adapter: self)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Valkyrie::Persistence::Solr::QueryService] The solr query
|
|
23
|
+
# service.
|
|
24
|
+
def query_service
|
|
25
|
+
Valkyrie::Persistence::Solr::QueryService.new(connection: connection, resource_factory: resource_factory)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Valkyrie::Persistence::Solr::ResourceFactory] A resource factory
|
|
29
|
+
# to convert a resource to a solr document and back.
|
|
30
|
+
def resource_factory
|
|
31
|
+
Valkyrie::Persistence::Solr::ResourceFactory.new(resource_indexer: resource_indexer)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class NullIndexer
|
|
35
|
+
def initialize(_); end
|
|
36
|
+
|
|
37
|
+
def to_solr
|
|
38
|
+
{}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Valkyrie::Persistence::Solr
|
|
3
|
+
class ModelConverter
|
|
4
|
+
attr_reader :resource, :resource_factory
|
|
5
|
+
delegate :resource_indexer, to: :resource_factory
|
|
6
|
+
def initialize(resource, resource_factory:)
|
|
7
|
+
@resource = resource
|
|
8
|
+
@resource_factory = resource_factory
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def convert!
|
|
12
|
+
to_h.merge(internal_resource_ssim: [resource.internal_resource]).merge(indexer_solr(resource))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def indexer_solr(resource)
|
|
16
|
+
resource_indexer.new(resource: resource).to_solr
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [String] The solr document ID
|
|
20
|
+
def id
|
|
21
|
+
"id-#{resource.id}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [String] ISO-8601 timestamp in UTC of the created_at for this solr
|
|
25
|
+
# document.
|
|
26
|
+
def created_at
|
|
27
|
+
resource_attributes[:created_at] || Time.current.utc.iso8601
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Hash] Solr document to index.
|
|
31
|
+
def to_h
|
|
32
|
+
{
|
|
33
|
+
"id": id,
|
|
34
|
+
"created_at_dtsi": created_at
|
|
35
|
+
}.merge(attribute_hash)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def attribute_hash
|
|
41
|
+
properties.each_with_object({}) do |property, hsh|
|
|
42
|
+
SolrMapperValue.for(Property.new(property, resource_attributes[property])).result.apply_to(hsh)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def properties
|
|
47
|
+
resource_attributes.keys - [:id, :created_at, :updated_at]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def resource_attributes
|
|
51
|
+
@resource_attributes ||= resource.attributes
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# A container resource for holding a `key`, `value, and `scope` of a value
|
|
56
|
+
# in a resource together for casting.
|
|
57
|
+
class Property
|
|
58
|
+
attr_reader :key, :value, :scope
|
|
59
|
+
# @param key [Symbol] Property identifier.
|
|
60
|
+
# @param value [Object] Value or list of values which are underneath the
|
|
61
|
+
# key.
|
|
62
|
+
# @param scope [Object] The resource or point where the key and values
|
|
63
|
+
# came from.
|
|
64
|
+
def initialize(key, value, scope = [])
|
|
65
|
+
@key = key
|
|
66
|
+
@value = value
|
|
67
|
+
@scope = scope
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# Represents a key/value combination in the solr document, used for isolating logic around
|
|
73
|
+
# how to apply a value to a hash.
|
|
74
|
+
class SolrRow
|
|
75
|
+
attr_reader :key, :fields, :values
|
|
76
|
+
# @param key [Symbol] Solr key.
|
|
77
|
+
# @param fields [Array<Symbol>] Field suffixes to index into.
|
|
78
|
+
# @param values [Array] Values to index into the given fields.
|
|
79
|
+
def initialize(key:, fields:, values:)
|
|
80
|
+
@key = key
|
|
81
|
+
@fields = Array.wrap(fields)
|
|
82
|
+
@values = Array.wrap(values)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @param hsh [Hash] The solr hash to apply to.
|
|
86
|
+
# @return [Hash] The updated solr hash.
|
|
87
|
+
def apply_to(hsh)
|
|
88
|
+
return hsh if values.blank?
|
|
89
|
+
fields.each do |field|
|
|
90
|
+
hsh["#{key}_#{field}".to_sym] ||= []
|
|
91
|
+
hsh["#{key}_#{field}".to_sym] += values
|
|
92
|
+
end
|
|
93
|
+
hsh
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# Wraps up multiple SolrRows to apply them all at once, while looking like
|
|
99
|
+
# just one.
|
|
100
|
+
class CompositeSolrRow
|
|
101
|
+
attr_reader :solr_rows
|
|
102
|
+
def initialize(solr_rows)
|
|
103
|
+
@solr_rows = solr_rows
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @see Valkyrie::Persistence::Solr::Mapper::SolrRow#apply_to
|
|
107
|
+
def apply_to(hsh)
|
|
108
|
+
solr_rows.each do |solr_row|
|
|
109
|
+
solr_row.apply_to(hsh)
|
|
110
|
+
end
|
|
111
|
+
hsh
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Container for casting mappers.
|
|
116
|
+
class SolrMapperValue < ::Valkyrie::ValueMapper
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Casts nested resources into a JSON string in solr.
|
|
120
|
+
class NestedObjectValue < ::Valkyrie::ValueMapper
|
|
121
|
+
SolrMapperValue.register(self)
|
|
122
|
+
def self.handles?(value)
|
|
123
|
+
value.value.is_a?(Hash)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def result
|
|
127
|
+
SolrRow.new(key: value.key, fields: ["tsim"], values: "serialized-#{value.value.to_json}")
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Casts enumerable values one by one.
|
|
132
|
+
class EnumerableValue < ::Valkyrie::ValueMapper
|
|
133
|
+
SolrMapperValue.register(self)
|
|
134
|
+
def self.handles?(value)
|
|
135
|
+
value.is_a?(Property) && value.value.is_a?(Array)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def result
|
|
139
|
+
CompositeSolrRow.new(
|
|
140
|
+
value.value.map do |val|
|
|
141
|
+
calling_mapper.for(Property.new(value.key, val, value.value)).result
|
|
142
|
+
end
|
|
143
|
+
)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Skips nil values.
|
|
148
|
+
class NilPropertyValue < ::Valkyrie::ValueMapper
|
|
149
|
+
SolrMapperValue.register(self)
|
|
150
|
+
def self.handles?(value)
|
|
151
|
+
value.is_a?(Property) && value.value.nil?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def result
|
|
155
|
+
SolrRow.new(key: value.key, fields: [], values: nil)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Casts {Valkyrie::ID} values into a recognizable string in solr.
|
|
160
|
+
class IDPropertyValue < ::Valkyrie::ValueMapper
|
|
161
|
+
SolrMapperValue.register(self)
|
|
162
|
+
def self.handles?(value)
|
|
163
|
+
value.is_a?(Property) && value.value.is_a?(::Valkyrie::ID)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def result
|
|
167
|
+
calling_mapper.for(Property.new(value.key, "id-#{value.value.id}")).result
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Casts {RDF::URI} values into a recognizable string in solr.
|
|
172
|
+
class URIPropertyValue < ::Valkyrie::ValueMapper
|
|
173
|
+
SolrMapperValue.register(self)
|
|
174
|
+
def self.handles?(value)
|
|
175
|
+
value.is_a?(Property) && value.value.is_a?(::RDF::URI)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def result
|
|
179
|
+
calling_mapper.for(Property.new(value.key, "uri-#{value.value}")).result
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Casts {Integer} values into a recognizable string in Solr.
|
|
184
|
+
class IntegerPropertyValue < ::Valkyrie::ValueMapper
|
|
185
|
+
SolrMapperValue.register(self)
|
|
186
|
+
def self.handles?(value)
|
|
187
|
+
value.is_a?(Property) && value.value.is_a?(Integer)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def result
|
|
191
|
+
calling_mapper.for(Property.new(value.key, "integer-#{value.value}")).result
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Casts {DateTime} values into a recognizable string in Solr.
|
|
196
|
+
class DateTimePropertyValue < ::Valkyrie::ValueMapper
|
|
197
|
+
SolrMapperValue.register(self)
|
|
198
|
+
def self.handles?(value)
|
|
199
|
+
value.is_a?(Property) && (value.value.is_a?(Time) || value.value.is_a?(DateTime))
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def result
|
|
203
|
+
calling_mapper.for(Property.new(value.key, "datetime-#{JSON.parse(to_datetime(value.value).to_json)}")).result
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
private
|
|
207
|
+
|
|
208
|
+
def to_datetime(value)
|
|
209
|
+
return value.utc if value.is_a?(DateTime)
|
|
210
|
+
return value.to_datetime.utc if value.respond_to?(:to_datetime)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Handles casting language-tagged strings when there are both
|
|
215
|
+
# language-tagged and non-language-tagged strings in Solr. Assumes English
|
|
216
|
+
# for non-language-tagged strings.
|
|
217
|
+
class SharedStringPropertyValue < ::Valkyrie::ValueMapper
|
|
218
|
+
SolrMapperValue.register(self)
|
|
219
|
+
def self.handles?(value)
|
|
220
|
+
value.is_a?(Property) && value.value.is_a?(String) && value.scope.find { |x| x.is_a?(::RDF::Literal) }.present?
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def result
|
|
224
|
+
CompositeSolrRow.new(
|
|
225
|
+
[
|
|
226
|
+
calling_mapper.for(Property.new(value.key, value.value)).result,
|
|
227
|
+
calling_mapper.for(Property.new("#{value.key}_lang", "eng")).result
|
|
228
|
+
]
|
|
229
|
+
)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Handles casting strings.
|
|
234
|
+
class StringPropertyValue < ::Valkyrie::ValueMapper
|
|
235
|
+
SolrMapperValue.register(self)
|
|
236
|
+
def self.handles?(value)
|
|
237
|
+
value.is_a?(Property) && value.value.is_a?(String)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def result
|
|
241
|
+
SolrRow.new(key: value.key, fields: fields, values: value.value)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def fields
|
|
245
|
+
if value.value.length > 1000
|
|
246
|
+
[:tsim]
|
|
247
|
+
else
|
|
248
|
+
[:tsim, :ssim, :tesim]
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Handles casting language-typed {RDF::Literal}s
|
|
254
|
+
class LiteralPropertyValue < ::Valkyrie::ValueMapper
|
|
255
|
+
SolrMapperValue.register(self)
|
|
256
|
+
def self.handles?(value)
|
|
257
|
+
value.is_a?(Property) && value.value.is_a?(::RDF::Literal)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def result
|
|
261
|
+
CompositeSolrRow.new(
|
|
262
|
+
[
|
|
263
|
+
calling_mapper.for(Property.new(value.key, value.value.to_s)).result,
|
|
264
|
+
calling_mapper.for(Property.new("#{value.key}_lang", value.value.language.to_s)).result
|
|
265
|
+
]
|
|
266
|
+
)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|