valkyrie 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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