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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -3
  3. data/.rubocop.yml +28 -0
  4. data/Gemfile +6 -1
  5. data/README.md +145 -10
  6. data/Rakefile +59 -1
  7. data/bin/console +1 -1
  8. data/config/valkyrie.yml +8 -0
  9. data/db/config.yml +17 -0
  10. data/db/migrate/20160111215816_enable_uuid_extension.rb +6 -0
  11. data/db/migrate/20161007101725_create_orm_resources.rb +10 -0
  12. data/db/migrate/20170124135846_add_model_type_to_orm_resources.rb +6 -0
  13. data/db/migrate/20170531004548_change_model_type_to_internal_model.rb +6 -0
  14. data/db/schema.rb +65 -0
  15. data/db/seeds.rb +8 -0
  16. data/lib/config/database_connection.rb +15 -0
  17. data/lib/generators/valkyrie/resource_generator.rb +27 -0
  18. data/lib/generators/valkyrie/templates/resource.rb.erb +9 -0
  19. data/lib/generators/valkyrie/templates/resource_spec.rb.erb +13 -0
  20. data/lib/valkyrie.rb +76 -1
  21. data/lib/valkyrie/adapter_container.rb +12 -0
  22. data/lib/valkyrie/change_set.rb +84 -0
  23. data/lib/valkyrie/decorators/decorator_list.rb +15 -0
  24. data/lib/valkyrie/decorators/decorator_with_arguments.rb +14 -0
  25. data/lib/valkyrie/derivative_service.rb +42 -0
  26. data/lib/valkyrie/engine.rb +10 -0
  27. data/lib/valkyrie/file_characterization_service.rb +42 -0
  28. data/lib/valkyrie/id.rb +32 -0
  29. data/lib/valkyrie/indexers/access_controls_indexer.rb +19 -0
  30. data/lib/valkyrie/local_file_service.rb +11 -0
  31. data/lib/valkyrie/metadata_adapter.rb +22 -0
  32. data/lib/valkyrie/persist_derivatives.rb +29 -0
  33. data/lib/valkyrie/persistence.rb +14 -0
  34. data/lib/valkyrie/persistence/buffered_persister.rb +28 -0
  35. data/lib/valkyrie/persistence/composite_persister.rb +29 -0
  36. data/lib/valkyrie/persistence/delete_tracking_buffer.rb +21 -0
  37. data/lib/valkyrie/persistence/fedora.rb +11 -0
  38. data/lib/valkyrie/persistence/fedora/list_node.rb +88 -0
  39. data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +45 -0
  40. data/lib/valkyrie/persistence/fedora/ordered_list.rb +146 -0
  41. data/lib/valkyrie/persistence/fedora/ordered_reader.rb +28 -0
  42. data/lib/valkyrie/persistence/fedora/persister.rb +47 -0
  43. data/lib/valkyrie/persistence/fedora/persister/model_converter.rb +199 -0
  44. data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +338 -0
  45. data/lib/valkyrie/persistence/fedora/persister/resource_factory.rb +21 -0
  46. data/lib/valkyrie/persistence/fedora/query_service.rb +80 -0
  47. data/lib/valkyrie/persistence/memory.rb +8 -0
  48. data/lib/valkyrie/persistence/memory/metadata_adapter.rb +22 -0
  49. data/lib/valkyrie/persistence/memory/persister.rb +58 -0
  50. data/lib/valkyrie/persistence/memory/query_service.rb +86 -0
  51. data/lib/valkyrie/persistence/postgres.rb +6 -0
  52. data/lib/valkyrie/persistence/postgres/metadata_adapter.rb +20 -0
  53. data/lib/valkyrie/persistence/postgres/orm.rb +9 -0
  54. data/lib/valkyrie/persistence/postgres/orm/resource.rb +7 -0
  55. data/lib/valkyrie/persistence/postgres/orm_converter.rb +118 -0
  56. data/lib/valkyrie/persistence/postgres/persister.rb +33 -0
  57. data/lib/valkyrie/persistence/postgres/queries.rb +8 -0
  58. data/lib/valkyrie/persistence/postgres/queries/find_inverse_references_query.rb +31 -0
  59. data/lib/valkyrie/persistence/postgres/queries/find_members_query.rb +33 -0
  60. data/lib/valkyrie/persistence/postgres/queries/find_references_query.rb +33 -0
  61. data/lib/valkyrie/persistence/postgres/query_service.rb +53 -0
  62. data/lib/valkyrie/persistence/postgres/resource_converter.rb +18 -0
  63. data/lib/valkyrie/persistence/postgres/resource_factory.rb +30 -0
  64. data/lib/valkyrie/persistence/solr.rb +6 -0
  65. data/lib/valkyrie/persistence/solr/metadata_adapter.rb +42 -0
  66. data/lib/valkyrie/persistence/solr/model_converter.rb +270 -0
  67. data/lib/valkyrie/persistence/solr/orm_converter.rb +252 -0
  68. data/lib/valkyrie/persistence/solr/persister.rb +32 -0
  69. data/lib/valkyrie/persistence/solr/queries.rb +11 -0
  70. data/lib/valkyrie/persistence/solr/queries/default_paginator.rb +16 -0
  71. data/lib/valkyrie/persistence/solr/queries/find_all_query.rb +33 -0
  72. data/lib/valkyrie/persistence/solr/queries/find_by_id_query.rb +24 -0
  73. data/lib/valkyrie/persistence/solr/queries/find_inverse_references_query.rb +30 -0
  74. data/lib/valkyrie/persistence/solr/queries/find_members_query.rb +43 -0
  75. data/lib/valkyrie/persistence/solr/queries/find_references_query.rb +34 -0
  76. data/lib/valkyrie/persistence/solr/query_service.rb +48 -0
  77. data/lib/valkyrie/persistence/solr/repository.rb +36 -0
  78. data/lib/valkyrie/persistence/solr/resource_factory.rb +24 -0
  79. data/lib/valkyrie/rdf_patches.rb +17 -0
  80. data/lib/valkyrie/resource.rb +106 -0
  81. data/lib/valkyrie/resource/access_controls.rb +13 -0
  82. data/lib/valkyrie/specs/shared_specs.rb +10 -0
  83. data/lib/valkyrie/specs/shared_specs/change_set_persister.rb +60 -0
  84. data/lib/valkyrie/specs/shared_specs/derivative_service.rb +30 -0
  85. data/lib/valkyrie/specs/shared_specs/file.rb +12 -0
  86. data/lib/valkyrie/specs/shared_specs/file_characterization_service.rb +33 -0
  87. data/lib/valkyrie/specs/shared_specs/metadata_adapter.rb +10 -0
  88. data/lib/valkyrie/specs/shared_specs/persister.rb +154 -0
  89. data/lib/valkyrie/specs/shared_specs/queries.rb +128 -0
  90. data/lib/valkyrie/specs/shared_specs/resource.rb +71 -0
  91. data/lib/valkyrie/specs/shared_specs/storage_adapter.rb +44 -0
  92. data/lib/valkyrie/storage.rb +8 -0
  93. data/lib/valkyrie/storage/disk.rb +55 -0
  94. data/lib/valkyrie/storage/fedora.rb +71 -0
  95. data/lib/valkyrie/storage/memory.rb +31 -0
  96. data/lib/valkyrie/storage_adapter.rb +100 -0
  97. data/lib/valkyrie/types.rb +34 -0
  98. data/lib/valkyrie/value_mapper.rb +67 -0
  99. data/lib/valkyrie/version.rb +2 -1
  100. data/lib/valkyrie/vocab/pcdm_use.rb +73 -0
  101. data/valkyrie.gemspec +33 -7
  102. metadata +462 -7
  103. data/.travis.yml +0 -5
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence::Fedora
3
+ class Persister
4
+ class ResourceFactory
5
+ require 'valkyrie/persistence/fedora/persister/model_converter'
6
+ require 'valkyrie/persistence/fedora/persister/orm_converter'
7
+ attr_reader :adapter
8
+ def initialize(adapter:)
9
+ @adapter = adapter
10
+ end
11
+
12
+ def from_resource(resource:)
13
+ ModelConverter.new(resource: resource, adapter: adapter).convert
14
+ end
15
+
16
+ def to_resource(object:)
17
+ OrmConverter.new(object: object, adapter: adapter).convert
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence::Fedora
3
+ class QueryService
4
+ attr_reader :adapter
5
+ delegate :connection, :resource_factory, to: :adapter
6
+ def initialize(adapter:)
7
+ @adapter = adapter
8
+ end
9
+
10
+ def find_by(id:)
11
+ uri = adapter.id_to_uri(id)
12
+ begin
13
+ resource = Ldp::Resource.for(connection, uri, connection.get(uri))
14
+ resource_factory.to_resource(object: resource)
15
+ rescue ::Ldp::Gone, ::Ldp::NotFound
16
+ raise ::Valkyrie::Persistence::ObjectNotFoundError
17
+ end
18
+ end
19
+
20
+ def find_parents(resource:)
21
+ content = content_with_inbound(id: resource.id)
22
+ parent_ids = content.graph.query([nil, RDF::Vocab::ORE.proxyFor, nil]).map(&:subject).map { |x| x.to_s.gsub(/#.*/, '') }.map { |x| adapter.uri_to_id(x) }
23
+ parent_ids.lazy.map do |id|
24
+ find_by(id: id)
25
+ end
26
+ end
27
+
28
+ def include_uris
29
+ [
30
+ ::RDF::Vocab::Fcrepo4.InboundReferences
31
+ ]
32
+ end
33
+
34
+ def find_members(resource:)
35
+ Array(resource.member_ids).lazy.map do |id|
36
+ find_by(id: id)
37
+ end.select(&:present?)
38
+ end
39
+
40
+ def find_all
41
+ resource = Ldp::Resource.for(connection, adapter.base_path, connection.get(adapter.base_path))
42
+ ids = resource.graph.query([nil, RDF::Vocab::LDP.contains, nil]).map(&:object).map { |x| adapter.uri_to_id(x) }
43
+ ids.lazy.map do |id|
44
+ find_by(id: id)
45
+ end
46
+ rescue ::Ldp::NotFound
47
+ []
48
+ end
49
+
50
+ def find_all_of_model(model:)
51
+ find_all.select do |m|
52
+ m.is_a?(model)
53
+ end
54
+ end
55
+
56
+ def find_references_by(resource:, property:)
57
+ (resource[property] || []).select { |x| x.is_a?(Valkyrie::ID) }.lazy.map do |id|
58
+ find_by(id: id)
59
+ end
60
+ end
61
+
62
+ def content_with_inbound(id:)
63
+ uri = adapter.id_to_uri(id)
64
+ connection.get(uri) do |req|
65
+ prefer_headers = Ldp::PreferHeaders.new(req.headers["Prefer"])
66
+ prefer_headers.include = prefer_headers.include | include_uris
67
+ req.headers["Prefer"] = prefer_headers.to_s
68
+ end
69
+ end
70
+
71
+ def find_inverse_references_by(resource:, property:)
72
+ content = content_with_inbound(id: resource.id)
73
+ property_uri = RDF::URI("http://example.com/predicate/#{property}")
74
+ ids = content.graph.query([nil, property_uri, nil]).map(&:subject).map { |x| x.to_s.gsub(/#.*/, '') }.map { |x| adapter.uri_to_id(x) }
75
+ ids.lazy.map do |id|
76
+ find_by(id: id)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence
3
+ module Memory
4
+ require 'valkyrie/persistence/memory/metadata_adapter'
5
+ require 'valkyrie/persistence/memory/persister'
6
+ require 'valkyrie/persistence/memory/query_service'
7
+ end
8
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence::Memory
3
+ class MetadataAdapter
4
+ attr_writer :cache
5
+
6
+ # @return [Valkyrie::Persistence::Memory::Persister] A memory persister for
7
+ # this adapter.
8
+ def persister
9
+ Valkyrie::Persistence::Memory::Persister.new(self)
10
+ end
11
+
12
+ # @return [Valkyrie::Persistence::Memory::QueryService] A query service for
13
+ # this adapter.
14
+ def query_service
15
+ Valkyrie::Persistence::Memory::QueryService.new(adapter: self)
16
+ end
17
+
18
+ def cache
19
+ @cache ||= {}
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence::Memory
3
+ class Persister
4
+ attr_reader :adapter
5
+ delegate :cache, to: :adapter
6
+ # @param adapter [Valkyrie::Persistence::Memory::MetadataAdapter] The memory adapter which
7
+ # holds the cache for this persister.
8
+ def initialize(adapter)
9
+ @adapter = adapter
10
+ end
11
+
12
+ # @param resource [Valkyrie::Resource] The resource to save.
13
+ # @return [Valkyrie::Resource] The resource with an `#id` value generated by the
14
+ # persistence backend.
15
+ def save(resource:)
16
+ resource = generate_id(resource) if resource.id.blank?
17
+ resource.updated_at = Time.current
18
+ normalize_dates!(resource)
19
+ cache[resource.id] = resource
20
+ end
21
+
22
+ # @param resources [Array<Valkyrie::Resource>] List of resources to save.
23
+ # @return [Array<Valkyrie::Resource>] List of resources with an `#id` value
24
+ # generated by the persistence backend.
25
+ def save_all(resources:)
26
+ resources.map do |resource|
27
+ save(resource: resource)
28
+ end
29
+ end
30
+
31
+ # @param resource [Valkyrie::Resource] The resource to delete from the persistence
32
+ # backend.
33
+ def delete(resource:)
34
+ cache.delete(resource.id)
35
+ end
36
+
37
+ private
38
+
39
+ def generate_id(resource)
40
+ resource.new(id: SecureRandom.uuid, created_at: Time.current)
41
+ end
42
+
43
+ def normalize_dates!(resource)
44
+ resource.attributes.each { |k, v| resource.send("#{k}=", normalize_date_values(v)) }
45
+ end
46
+
47
+ def normalize_date_values(v)
48
+ return v.map { |val| normalize_date_value(val) } if v.is_a?(Array)
49
+ normalize_date_value(v)
50
+ end
51
+
52
+ def normalize_date_value(value)
53
+ return value.utc if value.is_a?(DateTime)
54
+ return value.to_datetime.utc if value.is_a?(Time)
55
+ value
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence::Memory
3
+ class QueryService
4
+ attr_reader :adapter
5
+ delegate :cache, to: :adapter
6
+ # @param adapter [Valkyrie::Persistence::Memory::MetadataAdapter] The adapter which
7
+ # has the cache to query.
8
+ def initialize(adapter:)
9
+ @adapter = adapter
10
+ end
11
+
12
+ # @param id [Valkyrie::ID] The ID to query for.
13
+ # @raise [Valkyrie::Persistence::ObjectNotFoundError] Raised when the ID
14
+ # isn't in the persistence backend.
15
+ # @return [Valkyrie::Resource] The object being searched for.
16
+ def find_by(id:)
17
+ cache[id] || raise(::Valkyrie::Persistence::ObjectNotFoundError)
18
+ end
19
+
20
+ # @return [Array<Valkyrie::Resource>] All objects in the persistence backend.
21
+ def find_all
22
+ cache.values
23
+ end
24
+
25
+ # @param resource [Class] Class to query for.
26
+ # @return [Array<Valkyrie::Resource>] All objects in the persistence backend
27
+ # with the given class.
28
+ def find_all_of_model(model:)
29
+ cache.values.select do |obj|
30
+ obj.is_a?(model)
31
+ end
32
+ end
33
+
34
+ # @param resource [Valkyrie::Resource] Model whose members are being searched for.
35
+ # @return [Array<Valkyrie::Resource>] All child objects referenced by `resource`'s
36
+ # `member_ids` method. Returned in order.
37
+ def find_members(resource:)
38
+ member_ids(resource: resource).map do |id|
39
+ find_by(id: id)
40
+ end
41
+ end
42
+
43
+ # @param resource [Valkyrie::Resource] Model whose property is being searched.
44
+ # @param property [Symbol] Property which, on the `resource`, contains {Valkyrie::ID}s which are
45
+ # to be de-referenced.
46
+ # @return [Array<Valkyrie::Resource>] All objects which are referenced by the
47
+ # `property` property on `resource`. Not necessarily in order.
48
+ def find_references_by(resource:, property:)
49
+ Array.wrap(resource[property]).map do |id|
50
+ find_by(id: id)
51
+ end
52
+ end
53
+
54
+ # @param resource [Valkyrie::Resource] The resource which is being referenced by
55
+ # other resources.
56
+ # @param property [Symbol] The property which, on other resources, is
57
+ # referencing the given `resource`
58
+ # @return [Array<Valkyrie::Resource>] All resources in the persistence backend
59
+ # which have the ID of the given `resource` in their `property` property. Not
60
+ # in order.
61
+ def find_inverse_references_by(resource:, property:)
62
+ find_all.select do |obj|
63
+ begin
64
+ Array.wrap(obj[property]).include?(resource.id)
65
+ rescue
66
+ false
67
+ end
68
+ end
69
+ end
70
+
71
+ # @param resource [Valkyrie::Resource] The resource whose parents are being searched
72
+ # for.
73
+ # @return [Array<Valkyrie::Resource>] All resources which are parents of the given
74
+ # `resource`. This means the resource's `id` appears in their `member_ids`
75
+ # array.
76
+ def find_parents(resource:)
77
+ cache.values.select do |record|
78
+ member_ids(resource: record).include?(resource.id)
79
+ end
80
+ end
81
+
82
+ def member_ids(resource:)
83
+ resource.member_ids || []
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence
3
+ module Postgres
4
+ require 'valkyrie/persistence/postgres/metadata_adapter'
5
+ end
6
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'valkyrie/persistence/postgres/persister'
3
+ require 'valkyrie/persistence/postgres/query_service'
4
+ module Valkyrie::Persistence::Postgres
5
+ class MetadataAdapter
6
+ # @return [Class] {Valkyrie::Persistence::Postgres::Persister}
7
+ def persister
8
+ Valkyrie::Persistence::Postgres::Persister.new(adapter: self)
9
+ end
10
+
11
+ # @return [Class] {Valkyrie::Persistence::Postgres::QueryService}
12
+ def query_service
13
+ Valkyrie::Persistence::Postgres::QueryService.new(adapter: self)
14
+ end
15
+
16
+ def resource_factory
17
+ Valkyrie::Persistence::Postgres::ResourceFactory
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ require 'valkyrie/persistence/postgres/orm/resource'
3
+ module Valkyrie::Persistence::Postgres
4
+ module ORM
5
+ def self.table_name_prefix
6
+ 'orm_'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence::Postgres
3
+ module ORM
4
+ class Resource < ActiveRecord::Base
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+ module Valkyrie::Persistence::Postgres
3
+ class ORMConverter
4
+ attr_reader :orm_object
5
+ def initialize(orm_object)
6
+ @orm_object = orm_object
7
+ end
8
+
9
+ def convert!
10
+ @resource ||= attributes[:internal_resource].constantize.new(attributes)
11
+ end
12
+
13
+ # @return [Hash] Valkyrie-style hash of attributes.
14
+ def attributes
15
+ @attributes ||= orm_object.attributes.merge(rdf_metadata).symbolize_keys
16
+ end
17
+
18
+ def rdf_metadata
19
+ @rdf_metadata ||= RDFMetadata.new(orm_object.metadata).result
20
+ end
21
+
22
+ class RDFMetadata
23
+ attr_reader :metadata
24
+ def initialize(metadata)
25
+ @metadata = metadata
26
+ end
27
+
28
+ def result
29
+ Hash[
30
+ metadata.map do |key, value|
31
+ [key, PostgresValue.for(value).result]
32
+ end
33
+ ]
34
+ end
35
+
36
+ class PostgresValue < ::Valkyrie::ValueMapper
37
+ end
38
+ # Converts {RDF::Literal} typed-literals from JSON-LD stored into an
39
+ # {RDF::Literal}
40
+ class HashValue < ::Valkyrie::ValueMapper
41
+ PostgresValue.register(self)
42
+ def self.handles?(value)
43
+ value.is_a?(Hash) && value["@value"]
44
+ end
45
+
46
+ def result
47
+ RDF::Literal.new(value["@value"], language: value["@language"])
48
+ end
49
+ end
50
+
51
+ # Converts stored IDs into {Valkyrie::ID}s
52
+ class IDValue < ::Valkyrie::ValueMapper
53
+ PostgresValue.register(self)
54
+ def self.handles?(value)
55
+ value.is_a?(Hash) && value["id"] && !value["internal_resource"]
56
+ end
57
+
58
+ def result
59
+ Valkyrie::ID.new(value["id"])
60
+ end
61
+ end
62
+
63
+ # Converts stored URIs into {RDF::URI}s
64
+ class URIValue < ::Valkyrie::ValueMapper
65
+ PostgresValue.register(self)
66
+ def self.handles?(value)
67
+ value.is_a?(Hash) && value["@id"]
68
+ end
69
+
70
+ def result
71
+ ::RDF::URI.new(value["@id"])
72
+ end
73
+ end
74
+
75
+ # Converts nested records into {Valkyrie::Resource}s
76
+ class NestedRecord < ::Valkyrie::ValueMapper
77
+ PostgresValue.register(self)
78
+ def self.handles?(value)
79
+ value.is_a?(Hash) && value.keys.length > 1
80
+ end
81
+
82
+ def result
83
+ RDFMetadata.new(value).result.symbolize_keys
84
+ end
85
+ end
86
+
87
+ class DateValue < ::Valkyrie::ValueMapper
88
+ PostgresValue.register(self)
89
+ def self.handles?(value)
90
+ return false unless value.is_a?(String)
91
+ return false unless value[4] == "-"
92
+ year = value.to_s[0..3]
93
+ return false unless year.length == 4 && year.to_i.to_s == year
94
+ DateTime.iso8601(value)
95
+ rescue
96
+ false
97
+ end
98
+
99
+ def result
100
+ DateTime.iso8601(value).utc
101
+ end
102
+ end
103
+
104
+ class EnumeratorValue < ::Valkyrie::ValueMapper
105
+ PostgresValue.register(self)
106
+ def self.handles?(value)
107
+ value.respond_to?(:each)
108
+ end
109
+
110
+ def result
111
+ value.map do |value|
112
+ calling_mapper.for(value).result
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end