valkyrie 3.3.0 → 3.5.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/.circleci/config.yml +56 -80
- data/.lando.yml +1 -1
- data/.tool-versions +1 -1
- data/Appraisals +7 -12
- data/CHANGELOG.md +17 -0
- data/Rakefile +5 -1
- data/gemfiles/{activerecord_5_2.gemfile → activerecord_7_1.gemfile} +1 -1
- data/gemfiles/{activerecord_6_0.gemfile → activerecord_7_2.gemfile} +1 -1
- data/gemfiles/faraday_1.gemfile +1 -1
- data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +1 -0
- data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +3 -2
- data/lib/valkyrie/persistence/fedora/query_service.rb +2 -1
- data/lib/valkyrie/persistence/shared/json_value_mapper.rb +1 -0
- data/lib/valkyrie/persistence/solr/model_converter.rb +1 -1
- data/lib/valkyrie/specs/shared_specs/queries.rb +10 -0
- data/lib/valkyrie/specs/shared_specs/storage_adapter.rb +20 -4
- data/lib/valkyrie/storage/disk.rb +10 -3
- data/lib/valkyrie/storage/fedora.rb +16 -7
- data/lib/valkyrie/storage/memory.rb +9 -2
- data/lib/valkyrie/storage/versioned_disk.rb +18 -7
- data/lib/valkyrie/version.rb +1 -1
- data/lib/valkyrie.rb +11 -1
- metadata +5 -6
- data/gemfiles/faraday_0.gemfile +0 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ba113a4df1fa120076006223d629be9d186f96736fbb363781bc78f6c038013
|
|
4
|
+
data.tar.gz: 89e485a082def7836f884354b136c081496b5a9f36e98c2f9f31127dc053ab28
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d3537379fb136ec2ca843e2dd13d85a22c46a9c74d94f1ca3cfb1ab32f4a193394ab1ff9deae649939e3260b0ba9e9d8f423f3fb87d40043d107ff646fb74bc
|
|
7
|
+
data.tar.gz: 4a908d4d2574d5017bc81af1683d714b028b5d1ab17e086ff0f8ea6d0a764348f3efd3f308aeedac4623956ccfce915a5c5d611ab84d7e9e2d08c22d5afe623a
|
data/.circleci/config.yml
CHANGED
|
@@ -9,7 +9,7 @@ jobs:
|
|
|
9
9
|
type: "string"
|
|
10
10
|
ruby:
|
|
11
11
|
description: "Ruby version"
|
|
12
|
-
default: "
|
|
12
|
+
default: "3.1.6"
|
|
13
13
|
type: "string"
|
|
14
14
|
docker:
|
|
15
15
|
- image: cimg/ruby:<< parameters.ruby >>
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
environment:
|
|
29
29
|
CATALINA_OPTS: "-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms512m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
|
|
30
30
|
JAVA_OPTIONS: "-Djetty.http.port=8998 -Dfcrepo.dynamic.jms.port=61618 -Dfcrepo.dynamic.stomp.port=61614"
|
|
31
|
-
- image: fcrepo/fcrepo:6.
|
|
31
|
+
- image: fcrepo/fcrepo:6.5.1-RC3-tomcat9
|
|
32
32
|
environment:
|
|
33
33
|
CATALINA_OPTS: "-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms512m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DisableExplicitGC -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true"
|
|
34
34
|
JAVA_OPTS: "-Djetty.http.port=8978 -Dfcrepo.dynamic.jms.port=61619 -Dfcrepo.dynamic.stomp.port=61615 -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true"
|
|
@@ -96,57 +96,45 @@ workflows:
|
|
|
96
96
|
build:
|
|
97
97
|
jobs:
|
|
98
98
|
- build:
|
|
99
|
-
gemfile: "gemfiles/
|
|
100
|
-
ruby: 3.
|
|
101
|
-
name: "Ruby3-
|
|
99
|
+
gemfile: "gemfiles/activerecord_7_2.gemfile"
|
|
100
|
+
ruby: 3.3.5
|
|
101
|
+
name: "Ruby3-3_rails7-2"
|
|
102
102
|
- build:
|
|
103
|
-
gemfile: "gemfiles/
|
|
104
|
-
ruby: 3.
|
|
105
|
-
name: "Ruby3-
|
|
103
|
+
gemfile: "gemfiles/activerecord_7_1.gemfile"
|
|
104
|
+
ruby: 3.3.5
|
|
105
|
+
name: "Ruby3-3_rails7-1"
|
|
106
106
|
- build:
|
|
107
107
|
gemfile: "gemfiles/activerecord_7_0.gemfile"
|
|
108
|
-
ruby: 3.
|
|
109
|
-
name: "Ruby3-
|
|
108
|
+
ruby: 3.3.5
|
|
109
|
+
name: "Ruby3-3_rails7-0"
|
|
110
110
|
- build:
|
|
111
|
-
gemfile: "gemfiles/
|
|
112
|
-
ruby: 3.
|
|
113
|
-
name: "Ruby3-
|
|
111
|
+
gemfile: "gemfiles/activerecord_7_2.gemfile"
|
|
112
|
+
ruby: 3.2.5
|
|
113
|
+
name: "Ruby3-2_rails7-2"
|
|
114
|
+
- build:
|
|
115
|
+
gemfile: "gemfiles/activerecord_7_1.gemfile"
|
|
116
|
+
ruby: 3.2.5
|
|
117
|
+
name: "Ruby3-2_rails7-1"
|
|
114
118
|
- build:
|
|
115
119
|
gemfile: "gemfiles/activerecord_7_0.gemfile"
|
|
116
|
-
ruby: 3.
|
|
117
|
-
name: "Ruby3-
|
|
120
|
+
ruby: 3.2.5
|
|
121
|
+
name: "Ruby3-2_rails7-0"
|
|
118
122
|
- build:
|
|
119
|
-
gemfile: "gemfiles/
|
|
120
|
-
ruby: 3.
|
|
121
|
-
name: "Ruby3-
|
|
123
|
+
gemfile: "gemfiles/activerecord_7_2.gemfile"
|
|
124
|
+
ruby: 3.1.6
|
|
125
|
+
name: "Ruby3-1_rails7-2"
|
|
122
126
|
- build:
|
|
123
|
-
gemfile: "gemfiles/
|
|
124
|
-
ruby:
|
|
125
|
-
name: "
|
|
127
|
+
gemfile: "gemfiles/activerecord_7_1.gemfile"
|
|
128
|
+
ruby: 3.1.6
|
|
129
|
+
name: "Ruby3-1_rails7-1"
|
|
126
130
|
- build:
|
|
127
|
-
gemfile: "gemfiles/
|
|
128
|
-
ruby:
|
|
129
|
-
name: "
|
|
131
|
+
gemfile: "gemfiles/activerecord_7_0.gemfile"
|
|
132
|
+
ruby: 3.1.6
|
|
133
|
+
name: "Ruby3-1_rails7-0"
|
|
130
134
|
- build:
|
|
131
135
|
gemfile: "gemfiles/faraday_1.gemfile"
|
|
132
|
-
ruby:
|
|
136
|
+
ruby: 3.1.6
|
|
133
137
|
name: "Faraday1"
|
|
134
|
-
- build:
|
|
135
|
-
gemfile: "gemfiles/faraday_0.gemfile"
|
|
136
|
-
ruby: 2.7.7
|
|
137
|
-
name: "Faraday0"
|
|
138
|
-
- build:
|
|
139
|
-
gemfile: "gemfiles/activerecord_6_0.gemfile"
|
|
140
|
-
ruby: 2.6.10
|
|
141
|
-
name: "Ruby2-6_Rails6-0"
|
|
142
|
-
- build:
|
|
143
|
-
gemfile: "gemfiles/activerecord_5_2.gemfile"
|
|
144
|
-
ruby: 2.7.7
|
|
145
|
-
name: "Ruby2-7_Rails5-2"
|
|
146
|
-
- build:
|
|
147
|
-
gemfile: "gemfiles/activerecord_5_2.gemfile"
|
|
148
|
-
ruby: 2.6.10
|
|
149
|
-
name: "Ruby2-6_Rails5-2"
|
|
150
138
|
|
|
151
139
|
nightly:
|
|
152
140
|
triggers:
|
|
@@ -158,54 +146,42 @@ workflows:
|
|
|
158
146
|
- master
|
|
159
147
|
jobs:
|
|
160
148
|
- build:
|
|
161
|
-
gemfile: "gemfiles/
|
|
162
|
-
ruby: 3.
|
|
163
|
-
name: "Ruby3-
|
|
149
|
+
gemfile: "gemfiles/activerecord_7_2.gemfile"
|
|
150
|
+
ruby: 3.3.5
|
|
151
|
+
name: "Ruby3-3_rails7-2"
|
|
164
152
|
- build:
|
|
165
|
-
gemfile: "gemfiles/
|
|
166
|
-
ruby: 3.
|
|
167
|
-
name: "Ruby3-
|
|
153
|
+
gemfile: "gemfiles/activerecord_7_1.gemfile"
|
|
154
|
+
ruby: 3.3.5
|
|
155
|
+
name: "Ruby3-3_rails7-1"
|
|
168
156
|
- build:
|
|
169
157
|
gemfile: "gemfiles/activerecord_7_0.gemfile"
|
|
170
|
-
ruby: 3.
|
|
171
|
-
name: "Ruby3-
|
|
158
|
+
ruby: 3.3.5
|
|
159
|
+
name: "Ruby3-3_rails7-0"
|
|
172
160
|
- build:
|
|
173
|
-
gemfile: "gemfiles/
|
|
174
|
-
ruby: 3.
|
|
175
|
-
name: "Ruby3-
|
|
161
|
+
gemfile: "gemfiles/activerecord_7_2.gemfile"
|
|
162
|
+
ruby: 3.2.5
|
|
163
|
+
name: "Ruby3-2_rails7-2"
|
|
164
|
+
- build:
|
|
165
|
+
gemfile: "gemfiles/activerecord_7_1.gemfile"
|
|
166
|
+
ruby: 3.2.5
|
|
167
|
+
name: "Ruby3-2_rails7-1"
|
|
176
168
|
- build:
|
|
177
169
|
gemfile: "gemfiles/activerecord_7_0.gemfile"
|
|
178
|
-
ruby: 3.
|
|
179
|
-
name: "Ruby3-
|
|
170
|
+
ruby: 3.2.5
|
|
171
|
+
name: "Ruby3-2_rails7-0"
|
|
180
172
|
- build:
|
|
181
|
-
gemfile: "gemfiles/
|
|
182
|
-
ruby: 3.
|
|
183
|
-
name: "Ruby3-
|
|
173
|
+
gemfile: "gemfiles/activerecord_7_2.gemfile"
|
|
174
|
+
ruby: 3.1.6
|
|
175
|
+
name: "Ruby3-1_rails7-2"
|
|
184
176
|
- build:
|
|
185
|
-
gemfile: "gemfiles/
|
|
186
|
-
ruby:
|
|
187
|
-
name: "
|
|
177
|
+
gemfile: "gemfiles/activerecord_7_1.gemfile"
|
|
178
|
+
ruby: 3.1.6
|
|
179
|
+
name: "Ruby3-1_rails7-1"
|
|
188
180
|
- build:
|
|
189
|
-
gemfile: "gemfiles/
|
|
190
|
-
ruby:
|
|
191
|
-
name: "
|
|
181
|
+
gemfile: "gemfiles/activerecord_7_0.gemfile"
|
|
182
|
+
ruby: 3.1.6
|
|
183
|
+
name: "Ruby3-1_rails7-0"
|
|
192
184
|
- build:
|
|
193
185
|
gemfile: "gemfiles/faraday_1.gemfile"
|
|
194
|
-
ruby:
|
|
186
|
+
ruby: 3.1.6
|
|
195
187
|
name: "Faraday1"
|
|
196
|
-
- build:
|
|
197
|
-
gemfile: "gemfiles/faraday_0.gemfile"
|
|
198
|
-
ruby: 2.7.7
|
|
199
|
-
name: "Faraday0"
|
|
200
|
-
- build:
|
|
201
|
-
gemfile: "gemfiles/activerecord_6_0.gemfile"
|
|
202
|
-
ruby: 2.6.10
|
|
203
|
-
name: "Ruby2-6_Rails6-0"
|
|
204
|
-
- build:
|
|
205
|
-
gemfile: "gemfiles/activerecord_5_2.gemfile"
|
|
206
|
-
ruby: 2.7.7
|
|
207
|
-
name: "Ruby2-7_Rails5-2"
|
|
208
|
-
- build:
|
|
209
|
-
gemfile: "gemfiles/activerecord_5_2.gemfile"
|
|
210
|
-
ruby: 2.6.10
|
|
211
|
-
name: "Ruby2-6_Rails5-2"
|
data/.lando.yml
CHANGED
data/.tool-versions
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ruby
|
|
1
|
+
ruby 3.3.5
|
data/Appraisals
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
appraise "activerecord-7-
|
|
4
|
-
gem "activerecord", "~> 7.
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
appraise "activerecord-6-0" do
|
|
8
|
-
gem "activerecord", "~> 6.0.0"
|
|
3
|
+
appraise "activerecord-7-2" do
|
|
4
|
+
gem "activerecord", "~> 7.2.0"
|
|
9
5
|
end
|
|
10
6
|
|
|
11
|
-
appraise "activerecord-
|
|
12
|
-
gem "activerecord", "~>
|
|
7
|
+
appraise "activerecord-7-1" do
|
|
8
|
+
gem "activerecord", "~> 7.1.0"
|
|
13
9
|
end
|
|
14
10
|
|
|
15
|
-
appraise "
|
|
16
|
-
gem "
|
|
17
|
-
gem "activerecord", "~> 6.0.0"
|
|
11
|
+
appraise "activerecord-7-0" do
|
|
12
|
+
gem "activerecord", "~> 7.0.0"
|
|
18
13
|
end
|
|
19
14
|
|
|
20
15
|
appraise "faraday-1" do
|
|
21
16
|
gem "faraday", "~> 1.0"
|
|
22
|
-
gem "activerecord", "~>
|
|
17
|
+
gem "activerecord", "~> 7.0.0"
|
|
23
18
|
end
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# v3.5.0 2024-12-10
|
|
2
|
+
|
|
3
|
+
* Provides new boolean configuration setting `auto_cast_iso8601_as_datetime` ([dchandekstark](https://github.com/dchandekstark))
|
|
4
|
+
* Align behavior of server managed properties with Fedora. ([dlpierce](https://github.com/dlpierce))
|
|
5
|
+
* Check for nil id to avoid InvalidURIError ([dlpierce](https://github.com/dlpierce))
|
|
6
|
+
* Support Fedora 6.5 ([dlpierce](https://github.com/dlpierce))
|
|
7
|
+
* Make storage adapters report their protocol string ([dlpierce](https://github.com/dlpierce))
|
|
8
|
+
|
|
9
|
+
# v3.4.0 2024-10-11
|
|
10
|
+
|
|
11
|
+
## Changes since last release
|
|
12
|
+
|
|
13
|
+
* Adds config setting index_tsim_only_threshold ([dchandekstark](https://github.com/dchandekstark))
|
|
14
|
+
* Fix related URIs for pairtree paths in Fedora. ([randalldfloyd](https://github.com/randalldfloyd))
|
|
15
|
+
* Return nil when #id_to_uri is passed empty strings. ([bwatson78](https://github.com/bwatson78))
|
|
16
|
+
* Add support for Ruby 3.3 and Rails 7.2 ([cjcolvar](https://github.com/cjcolvar))
|
|
17
|
+
|
|
1
18
|
# v3.3.0 2024-07-03
|
|
2
19
|
|
|
3
20
|
## Changes since last release
|
data/Rakefile
CHANGED
|
@@ -68,10 +68,14 @@ namespace :db do
|
|
|
68
68
|
ActiveRecord::Migrator.migrate(MIGRATIONS_DIR, version) do |migration|
|
|
69
69
|
scope.blank? || scope == migration.scope
|
|
70
70
|
end
|
|
71
|
-
|
|
71
|
+
elsif ActiveRecord.version < Gem::Version.new("7.2.0")
|
|
72
72
|
ActiveRecord::Base.connection.migration_context.migrate(version) do |migration|
|
|
73
73
|
scope.blank? || scope == migration.scope
|
|
74
74
|
end
|
|
75
|
+
else
|
|
76
|
+
ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths).migrate(version) do |migration|
|
|
77
|
+
scope.blank? || scope == migration.scope
|
|
78
|
+
end
|
|
75
79
|
end
|
|
76
80
|
ActiveRecord::Base.clear_cache!
|
|
77
81
|
ensure
|
data/gemfiles/faraday_1.gemfile
CHANGED
|
@@ -64,6 +64,7 @@ module Valkyrie::Persistence::Fedora
|
|
|
64
64
|
# @param [RDF::URI] id the Valkyrie ID
|
|
65
65
|
# @return [RDF::URI]
|
|
66
66
|
def id_to_uri(id)
|
|
67
|
+
return if id.to_s.empty?
|
|
67
68
|
prefix = ""
|
|
68
69
|
prefix = "#{pair_path(id)}/" if fedora_version == 4 || (fedora_version >= 6.5 && (pairtree_count * pairtree_length).positive?)
|
|
69
70
|
RDF::URI("#{connection_prefix}/#{prefix}#{CGI.escape(id.to_s)}")
|
|
@@ -105,7 +105,8 @@ module Valkyrie::Persistence::Fedora
|
|
|
105
105
|
# @param [Property] value
|
|
106
106
|
# @return [Boolean]
|
|
107
107
|
def self.handles?(value)
|
|
108
|
-
value.statement.
|
|
108
|
+
value.statement.predicate == RDF.type &&
|
|
109
|
+
value.statement.object.to_s.start_with?('http://www.w3.org/ns/ldp#', 'http://fedora.info/definitions/v4/repository#')
|
|
109
110
|
end
|
|
110
111
|
|
|
111
112
|
# Provide the NullApplicator Class for any Property in a deny listed namespace
|
|
@@ -562,7 +563,7 @@ module Valkyrie::Persistence::Fedora
|
|
|
562
563
|
# @return [Array<String>]
|
|
563
564
|
def denylist
|
|
564
565
|
[
|
|
565
|
-
"http://fedora.info/definitions",
|
|
566
|
+
"http://fedora.info/definitions/v4/repository#",
|
|
566
567
|
"http://www.iana.org/assignments/relation/last"
|
|
567
568
|
]
|
|
568
569
|
end
|
|
@@ -52,7 +52,7 @@ module Valkyrie::Persistence::Fedora
|
|
|
52
52
|
# @return [Array<RDF::URI>]
|
|
53
53
|
def include_uris
|
|
54
54
|
[
|
|
55
|
-
|
|
55
|
+
adapter.fedora_version >= 5 ? "http://fedora.info/definitions/fcrepo#PreferInboundReferences" : ::RDF::Vocab::Fcrepo4.InboundReferences
|
|
56
56
|
]
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -162,6 +162,7 @@ module Valkyrie::Persistence::Fedora
|
|
|
162
162
|
# @return [Valkyrie::Resource]
|
|
163
163
|
# @raise [Valkyrie::Persistence::ObjectNotFoundError]
|
|
164
164
|
def resource_from_uri(uri)
|
|
165
|
+
raise ::Valkyrie::Persistence::ObjectNotFoundError if uri.nil?
|
|
165
166
|
resource = Ldp::Resource.for(connection, uri, connection.get(uri))
|
|
166
167
|
resource_factory.to_resource(object: resource)
|
|
167
168
|
rescue ::Ldp::Gone, ::Ldp::NotFound
|
|
@@ -139,6 +139,7 @@ module Valkyrie::Persistence::Shared
|
|
|
139
139
|
# @return [Boolean]
|
|
140
140
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
141
141
|
def self.handles?(value)
|
|
142
|
+
return false unless ::Valkyrie.config.auto_cast_iso8601_as_datetime
|
|
142
143
|
return false unless value.is_a?(String)
|
|
143
144
|
return false unless value[4] == "-" && value[10] == "T"
|
|
144
145
|
year = value.to_s[0..3]
|
|
@@ -422,7 +422,7 @@ module Valkyrie::Persistence::Solr
|
|
|
422
422
|
# @see https://github.com/samvera-labs/valkyrie/blob/main/solr/config/schema.xml
|
|
423
423
|
# @return [Array<Symbol>]
|
|
424
424
|
def fields
|
|
425
|
-
if value.value.length >
|
|
425
|
+
if value.value.length > Valkyrie.config.index_tsim_only_threshold
|
|
426
426
|
[:tsim]
|
|
427
427
|
else
|
|
428
428
|
[:tsim, :ssim, :tesim, :tsi, :ssi, :tesi]
|
|
@@ -86,8 +86,13 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
|
86
86
|
expect { query_service.find_by(id: Valkyrie::ID.new("123123123")) }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
it 'returns a Valkyrie::Persistence::ObjectNotFoundError for an empty string' do
|
|
90
|
+
expect { query_service.find_by(id: '') }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
|
|
91
|
+
end
|
|
92
|
+
|
|
89
93
|
it 'raises an error if the id is not a Valkyrie::ID or a string' do
|
|
90
94
|
expect { query_service.find_by(id: 123) }.to raise_error ArgumentError
|
|
95
|
+
expect { query_service.find_by(id: nil) }.to raise_error ArgumentError
|
|
91
96
|
end
|
|
92
97
|
end
|
|
93
98
|
|
|
@@ -117,8 +122,13 @@ RSpec.shared_examples 'a Valkyrie query provider' do
|
|
|
117
122
|
expect { query_service.find_by_alternate_identifier(alternate_identifier: Valkyrie::ID.new("123123123")) }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
|
|
118
123
|
end
|
|
119
124
|
|
|
125
|
+
it "raises a Valkyrie::Persistence::ObjectNotFoundError for a non-found alternate identifier" do
|
|
126
|
+
expect { query_service.find_by_alternate_identifier(alternate_identifier: '') }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
|
|
127
|
+
end
|
|
128
|
+
|
|
120
129
|
it 'raises an error if the alternate identifier is not a Valkyrie::ID or a string' do
|
|
121
130
|
expect { query_service.find_by_alternate_identifier(alternate_identifier: 123) }.to raise_error ArgumentError
|
|
131
|
+
expect { query_service.find_by_alternate_identifier(alternate_identifier: nil) }.to raise_error ArgumentError
|
|
122
132
|
end
|
|
123
133
|
|
|
124
134
|
it 'can have multiple alternate identifiers' do
|
|
@@ -12,6 +12,7 @@ RSpec.shared_examples 'a Valkyrie::StorageAdapter' do
|
|
|
12
12
|
Valkyrie::Specs.send(:remove_const, :CustomResource)
|
|
13
13
|
end
|
|
14
14
|
subject { storage_adapter }
|
|
15
|
+
it { is_expected.to respond_to(:protocol) }
|
|
15
16
|
it { is_expected.to respond_to(:handles?).with_keywords(:id) }
|
|
16
17
|
it { is_expected.to respond_to(:find_by).with_keywords(:id) }
|
|
17
18
|
it { is_expected.to respond_to(:delete).with_keywords(:id) }
|
|
@@ -74,8 +75,9 @@ RSpec.shared_examples 'a Valkyrie::StorageAdapter' do
|
|
|
74
75
|
resource = Valkyrie::Specs::CustomResource.new(id: "test#{SecureRandom.uuid}")
|
|
75
76
|
sha1 = Digest::SHA1.file(file).to_s
|
|
76
77
|
size = file.size
|
|
77
|
-
|
|
78
|
+
uploaded_file = storage_adapter.upload(file: file, original_filename: 'foo.jpg', resource: resource, fake_upload_argument: true)
|
|
78
79
|
|
|
80
|
+
expect(uploaded_file).to be_kind_of Valkyrie::StorageAdapter::File
|
|
79
81
|
expect(uploaded_file).to respond_to(:checksum).with_keywords(:digests)
|
|
80
82
|
expect(uploaded_file).to respond_to(:valid?).with_keywords(:size, :digests)
|
|
81
83
|
expect(uploaded_file.checksum(digests: [Digest::SHA1.new])).to eq([sha1])
|
|
@@ -133,28 +135,42 @@ RSpec.shared_examples 'a Valkyrie::StorageAdapter' do
|
|
|
133
135
|
# Deleting a version should leave the current versions
|
|
134
136
|
if storage_adapter.supports?(:version_deletion)
|
|
135
137
|
storage_adapter.delete(id: uploaded_file.version_id)
|
|
136
|
-
|
|
138
|
+
remnants = storage_adapter.find_versions(id: uploaded_file.id)
|
|
139
|
+
expect(remnants.length).to eq 1
|
|
140
|
+
expect(remnants.first.version_id).to eq new_version.version_id
|
|
137
141
|
expect { storage_adapter.find_by(id: uploaded_file.version_id) }.to raise_error Valkyrie::StorageAdapter::FileNotFound
|
|
138
142
|
end
|
|
139
143
|
current_length = storage_adapter.find_versions(id: new_version.id).length
|
|
140
144
|
|
|
141
145
|
# Restoring a previous version is just pumping its file into upload_version
|
|
142
146
|
newest_version = storage_adapter.upload_version(file: new_version, id: new_version.id)
|
|
147
|
+
current_length += 1
|
|
143
148
|
expect(newest_version.version_id).not_to eq new_version.id
|
|
144
149
|
expect(storage_adapter.find_by(id: newest_version.id).version_id).to eq newest_version.version_id
|
|
145
150
|
|
|
146
151
|
# I can restore a version twice
|
|
147
152
|
newest_version = storage_adapter.upload_version(file: new_version, id: new_version.id)
|
|
153
|
+
current_length += 1
|
|
148
154
|
expect(newest_version.version_id).not_to eq new_version.id
|
|
149
155
|
expect(storage_adapter.find_by(id: newest_version.id).version_id).to eq newest_version.version_id
|
|
150
|
-
expect(storage_adapter.find_versions(id: newest_version.id).length).to eq current_length
|
|
156
|
+
expect(storage_adapter.find_versions(id: newest_version.id).length).to eq current_length
|
|
157
|
+
|
|
158
|
+
# Fedora 6.5 may not create versions when the timestamp is the same?
|
|
159
|
+
# See: https://fedora-repository.atlassian.net/browse/FCREPO-3958
|
|
160
|
+
sleep 1 if storage_adapter.supports?(:list_deleted_versions)
|
|
151
161
|
|
|
152
162
|
# NOTE: We originally wanted deleting the current record to push it into the
|
|
153
163
|
# versions history, but FCRepo 4/5/6 doesn't work that way, so we changed to
|
|
154
164
|
# instead make deleting delete everything.
|
|
155
165
|
storage_adapter.delete(id: new_version.id)
|
|
156
166
|
expect { storage_adapter.find_by(id: new_version.id) }.to raise_error Valkyrie::StorageAdapter::FileNotFound
|
|
157
|
-
|
|
167
|
+
|
|
168
|
+
if storage_adapter.supports?(:list_deleted_versions)
|
|
169
|
+
expect(storage_adapter.find_versions(id: new_version.id).length).to eq current_length
|
|
170
|
+
else
|
|
171
|
+
expect(storage_adapter.find_versions(id: new_version.id).length).to eq 0
|
|
172
|
+
end
|
|
173
|
+
|
|
158
174
|
ensure
|
|
159
175
|
f&.close
|
|
160
176
|
end
|
|
@@ -3,6 +3,8 @@ module Valkyrie::Storage
|
|
|
3
3
|
# Implements the DataMapper Pattern to store binary data on disk
|
|
4
4
|
class Disk
|
|
5
5
|
attr_reader :base_path, :path_generator, :file_mover
|
|
6
|
+
PROTOCOL = 'disk://'
|
|
7
|
+
|
|
6
8
|
def initialize(base_path:, path_generator: BucketedStorage, file_mover: FileUtils.method(:mv))
|
|
7
9
|
@base_path = Pathname.new(base_path.to_s)
|
|
8
10
|
@path_generator = path_generator.new(base_path: base_path)
|
|
@@ -18,13 +20,13 @@ module Valkyrie::Storage
|
|
|
18
20
|
new_path = path_generator.generate(resource: resource, file: file, original_filename: original_filename)
|
|
19
21
|
FileUtils.mkdir_p(new_path.parent)
|
|
20
22
|
file_mover.call(file.path, new_path)
|
|
21
|
-
find_by(id: Valkyrie::ID.new("
|
|
23
|
+
find_by(id: Valkyrie::ID.new("#{protocol}#{new_path}"))
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
# @param id [Valkyrie::ID]
|
|
25
27
|
# @return [Boolean] true if this adapter can handle this type of identifer
|
|
26
28
|
def handles?(id:)
|
|
27
|
-
id.to_s.start_with?("
|
|
29
|
+
id.to_s.start_with?("#{protocol}#{base_path}")
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
# @param feature [Symbol] Feature to test for.
|
|
@@ -33,8 +35,13 @@ module Valkyrie::Storage
|
|
|
33
35
|
false
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
# @return [String] identifier prefix
|
|
39
|
+
def protocol
|
|
40
|
+
PROTOCOL
|
|
41
|
+
end
|
|
42
|
+
|
|
36
43
|
def file_path(id)
|
|
37
|
-
id.to_s.gsub(
|
|
44
|
+
id.to_s.gsub(/^#{Regexp.escape(protocol)}/, '')
|
|
38
45
|
end
|
|
39
46
|
|
|
40
47
|
# Return the file associated with the given identifier
|
|
@@ -27,7 +27,7 @@ module Valkyrie::Storage
|
|
|
27
27
|
# @param id [Valkyrie::ID]
|
|
28
28
|
# @return [Boolean] true if this adapter can handle this type of identifer
|
|
29
29
|
def handles?(id:)
|
|
30
|
-
id.to_s.start_with?(
|
|
30
|
+
id.to_s.start_with?(protocol)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# @param feature [Symbol] Feature to test for.
|
|
@@ -36,9 +36,16 @@ module Valkyrie::Storage
|
|
|
36
36
|
return true if feature == :versions
|
|
37
37
|
# Fedora 6 auto versions and you can't delete versions.
|
|
38
38
|
return true if feature == :version_deletion && fedora_version < 6
|
|
39
|
+
# Fedora 6.5+ lists versions for deleted objects
|
|
40
|
+
return true if feature == :list_deleted_versions && fedora_version >= 6.5
|
|
39
41
|
false
|
|
40
42
|
end
|
|
41
43
|
|
|
44
|
+
# @return [String] identifier prefix
|
|
45
|
+
def protocol
|
|
46
|
+
PROTOCOL
|
|
47
|
+
end
|
|
48
|
+
|
|
42
49
|
# Return the file associated with the given identifier
|
|
43
50
|
# @param id [Valkyrie::ID]
|
|
44
51
|
# @return [Valkyrie::StorageAdapter::StreamFile]
|
|
@@ -61,7 +68,7 @@ module Valkyrie::Storage
|
|
|
61
68
|
# Fedora 6 auto versions, so check to see if there's a version for this
|
|
62
69
|
# initial upload. If not, then mint one (fedora 4/5)
|
|
63
70
|
version_id = current_version_id(id: valkyrie_identifier(uri: identifier)) || mint_version(identifier, latest_version(identifier))
|
|
64
|
-
perform_find(id: Valkyrie::ID.new(identifier.to_s.sub(/^.+\/\//,
|
|
71
|
+
perform_find(id: Valkyrie::ID.new(identifier.to_s.sub(/^.+\/\//, protocol)), version_id: version_id)
|
|
65
72
|
end
|
|
66
73
|
|
|
67
74
|
# @param id [Valkyrie::ID] ID of the Valkyrie::StorageAdapter::StreamFile to
|
|
@@ -77,7 +84,7 @@ module Valkyrie::Storage
|
|
|
77
84
|
end
|
|
78
85
|
upload_file(fedora_uri: uri, io: file)
|
|
79
86
|
version_id = mint_version(uri, latest_version(uri))
|
|
80
|
-
perform_find(id: Valkyrie::ID.new(uri.to_s.sub(/^.+\/\//,
|
|
87
|
+
perform_find(id: Valkyrie::ID.new(uri.to_s.sub(/^.+\/\//, protocol)), version_id: version_id)
|
|
81
88
|
end
|
|
82
89
|
|
|
83
90
|
# @param id [Valkyrie::ID]
|
|
@@ -88,7 +95,9 @@ module Valkyrie::Storage
|
|
|
88
95
|
version_list.map do |version|
|
|
89
96
|
id = valkyrie_identifier(uri: version["@id"])
|
|
90
97
|
perform_find(id: id, version_id: id)
|
|
91
|
-
|
|
98
|
+
rescue Valkyrie::StorageAdapter::FileNotFound
|
|
99
|
+
nil
|
|
100
|
+
end.compact
|
|
92
101
|
end
|
|
93
102
|
|
|
94
103
|
# Delete the file in Fedora associated with the given identifier.
|
|
@@ -197,12 +206,12 @@ module Valkyrie::Storage
|
|
|
197
206
|
# Translate the Valkrie ID into a URL for the fedora file
|
|
198
207
|
# @return [RDF::URI]
|
|
199
208
|
def fedora_identifier(id:)
|
|
200
|
-
identifier = id.to_s.sub(
|
|
209
|
+
identifier = id.to_s.sub(protocol, "#{connection.http.scheme}://")
|
|
201
210
|
RDF::URI(identifier)
|
|
202
211
|
end
|
|
203
212
|
|
|
204
213
|
def valkyrie_identifier(uri:)
|
|
205
|
-
id = uri.to_s.sub("http://",
|
|
214
|
+
id = uri.to_s.sub("http://", protocol)
|
|
206
215
|
Valkyrie::ID.new(id)
|
|
207
216
|
end
|
|
208
217
|
|
|
@@ -211,7 +220,7 @@ module Valkyrie::Storage
|
|
|
211
220
|
# @return [IOProxy]
|
|
212
221
|
def response(id:)
|
|
213
222
|
response = connection.http.get(fedora_identifier(id: id))
|
|
214
|
-
raise Valkyrie::StorageAdapter::FileNotFound unless response.success?
|
|
223
|
+
raise Valkyrie::StorageAdapter::FileNotFound, "HTTP #{response.status} #{response.body}" unless response.success?
|
|
215
224
|
IOProxy.new(response.body)
|
|
216
225
|
end
|
|
217
226
|
|
|
@@ -6,6 +6,8 @@ module Valkyrie::Storage
|
|
|
6
6
|
# in cases where you want to preserve real data
|
|
7
7
|
class Memory
|
|
8
8
|
attr_reader :cache
|
|
9
|
+
PROTOCOL = 'memory://'
|
|
10
|
+
|
|
9
11
|
def initialize
|
|
10
12
|
@cache = {}
|
|
11
13
|
end
|
|
@@ -16,7 +18,7 @@ module Valkyrie::Storage
|
|
|
16
18
|
# @param _extra_arguments [Hash] additional arguments which may be passed to other adapters
|
|
17
19
|
# @return [Valkyrie::StorageAdapter::StreamFile]
|
|
18
20
|
def upload(file:, original_filename:, resource: nil, **_extra_arguments)
|
|
19
|
-
identifier = Valkyrie::ID.new("
|
|
21
|
+
identifier = Valkyrie::ID.new("#{protocol}#{resource.id}")
|
|
20
22
|
version_id = Valkyrie::ID.new("#{identifier}##{SecureRandom.uuid}")
|
|
21
23
|
cache[identifier] ||= {}
|
|
22
24
|
cache[identifier][:current] = Valkyrie::StorageAdapter::StreamFile.new(id: identifier, io: file, version_id: version_id)
|
|
@@ -67,7 +69,7 @@ module Valkyrie::Storage
|
|
|
67
69
|
# @param id [Valkyrie::ID]
|
|
68
70
|
# @return [Boolean] true if this adapter can handle this type of identifer
|
|
69
71
|
def handles?(id:)
|
|
70
|
-
id.to_s.start_with?(
|
|
72
|
+
id.to_s.start_with?(protocol)
|
|
71
73
|
end
|
|
72
74
|
|
|
73
75
|
# @param feature [Symbol] Feature to test for.
|
|
@@ -83,6 +85,11 @@ module Valkyrie::Storage
|
|
|
83
85
|
end
|
|
84
86
|
end
|
|
85
87
|
|
|
88
|
+
# @return [String] identifier prefix
|
|
89
|
+
def protocol
|
|
90
|
+
PROTOCOL
|
|
91
|
+
end
|
|
92
|
+
|
|
86
93
|
def id_and_version(id)
|
|
87
94
|
id, version = id.to_s.split("#")
|
|
88
95
|
[Valkyrie::ID.new(id), version]
|
|
@@ -7,6 +7,8 @@ module Valkyrie::Storage
|
|
|
7
7
|
# with "deletionmarker" in the name of the file.
|
|
8
8
|
class VersionedDisk
|
|
9
9
|
attr_reader :base_path, :path_generator, :file_mover
|
|
10
|
+
PROTOCOL = 'versiondisk://'
|
|
11
|
+
|
|
10
12
|
def initialize(base_path:, path_generator: ::Valkyrie::Storage::Disk::BucketedStorage, file_mover: FileUtils.method(:cp))
|
|
11
13
|
@base_path = Pathname.new(base_path.to_s)
|
|
12
14
|
@path_generator = path_generator.new(base_path: base_path)
|
|
@@ -26,7 +28,7 @@ module Valkyrie::Storage
|
|
|
26
28
|
return sleep(0.001) && upload(file: file, original_filename: original_filename, resource: resource, paused: true, **extra_arguments) if !paused && File.exist?(new_path)
|
|
27
29
|
FileUtils.mkdir_p(new_path.parent)
|
|
28
30
|
file_mover.call(file.try(:path) || file.try(:disk_path), new_path)
|
|
29
|
-
find_by(id: Valkyrie::ID.new("
|
|
31
|
+
find_by(id: Valkyrie::ID.new("#{protocol}#{new_path}"))
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def current_timestamp
|
|
@@ -50,13 +52,13 @@ module Valkyrie::Storage
|
|
|
50
52
|
return sleep(0.001) && upload_version(id: id, file: file, paused: true) if !paused && File.exist?(new_path)
|
|
51
53
|
FileUtils.mkdir_p(new_path.parent)
|
|
52
54
|
file_mover.call(file.try(:path) || file.try(:disk_path), new_path)
|
|
53
|
-
find_by(id: Valkyrie::ID.new("
|
|
55
|
+
find_by(id: Valkyrie::ID.new("#{protocol}#{new_path}"))
|
|
54
56
|
end
|
|
55
57
|
|
|
56
58
|
# @param id [Valkyrie::ID]
|
|
57
59
|
# @return [Boolean] true if this adapter can handle this type of identifer
|
|
58
60
|
def handles?(id:)
|
|
59
|
-
id.to_s.start_with?("
|
|
61
|
+
id.to_s.start_with?("#{protocol}#{base_path}")
|
|
60
62
|
end
|
|
61
63
|
|
|
62
64
|
# @param feature [Symbol] Feature to test for.
|
|
@@ -66,6 +68,11 @@ module Valkyrie::Storage
|
|
|
66
68
|
false
|
|
67
69
|
end
|
|
68
70
|
|
|
71
|
+
# @return [String] identifier prefix
|
|
72
|
+
def protocol
|
|
73
|
+
PROTOCOL
|
|
74
|
+
end
|
|
75
|
+
|
|
69
76
|
# Return the file associated with the given identifier
|
|
70
77
|
# @param id [Valkyrie::ID]
|
|
71
78
|
# @return [Valkyrie::StorageAdapter::File]
|
|
@@ -95,7 +102,7 @@ module Valkyrie::Storage
|
|
|
95
102
|
# @return [Array<Valkyrie::StorageAdapter::File>]
|
|
96
103
|
def find_versions(id:)
|
|
97
104
|
version_files(id: id).select { |x| !x.to_s.include?("deletionmarker") }.map do |file|
|
|
98
|
-
find_by(id: Valkyrie::ID.new("
|
|
105
|
+
find_by(id: Valkyrie::ID.new("#{protocol}#{file}"))
|
|
99
106
|
end
|
|
100
107
|
end
|
|
101
108
|
|
|
@@ -106,7 +113,7 @@ module Valkyrie::Storage
|
|
|
106
113
|
end
|
|
107
114
|
|
|
108
115
|
def file_path(version_id)
|
|
109
|
-
version_id.to_s.gsub(
|
|
116
|
+
version_id.to_s.gsub(/^#{Regexp.escape(protocol)}/, '')
|
|
110
117
|
end
|
|
111
118
|
|
|
112
119
|
# @return VersionId A VersionId value that's resolved a current reference,
|
|
@@ -128,6 +135,10 @@ module Valkyrie::Storage
|
|
|
128
135
|
@id = id
|
|
129
136
|
end
|
|
130
137
|
|
|
138
|
+
def protocol
|
|
139
|
+
PROTOCOL
|
|
140
|
+
end
|
|
141
|
+
|
|
131
142
|
def current_reference_id
|
|
132
143
|
self.class.new(Valkyrie::ID.new(string_id.gsub(version, "current")))
|
|
133
144
|
end
|
|
@@ -139,13 +150,13 @@ module Valkyrie::Storage
|
|
|
139
150
|
end
|
|
140
151
|
|
|
141
152
|
def file_path
|
|
142
|
-
@file_path ||= string_id.gsub(
|
|
153
|
+
@file_path ||= string_id.gsub(/^#{Regexp.escape(protocol)}/, '')
|
|
143
154
|
end
|
|
144
155
|
|
|
145
156
|
def version_files
|
|
146
157
|
root = Pathname.new(file_path)
|
|
147
158
|
root.parent.children.select { |file| file.basename.to_s.end_with?(filename) }.sort.reverse.map do |file|
|
|
148
|
-
VersionId.new(Valkyrie::ID.new("
|
|
159
|
+
VersionId.new(Valkyrie::ID.new("#{protocol}#{file}"))
|
|
149
160
|
end
|
|
150
161
|
end
|
|
151
162
|
|
data/lib/valkyrie/version.rb
CHANGED
data/lib/valkyrie.rb
CHANGED
|
@@ -97,6 +97,14 @@ module Valkyrie
|
|
|
97
97
|
Valkyrie::StorageAdapter.find(self[:storage_adapter].to_sym)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
def index_tsim_only_threshold
|
|
101
|
+
self[:index_tsim_only_threshold].to_i
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def auto_cast_iso8601_as_datetime
|
|
105
|
+
self[:auto_cast_iso8601_as_datetime]
|
|
106
|
+
end
|
|
107
|
+
|
|
100
108
|
# @api public
|
|
101
109
|
#
|
|
102
110
|
# The returned anonymous method (e.g. responds to #call) has a signature of
|
|
@@ -118,7 +126,9 @@ module Valkyrie
|
|
|
118
126
|
|
|
119
127
|
def defaults
|
|
120
128
|
{
|
|
121
|
-
resource_class_resolver: method(:default_resource_class_resolver)
|
|
129
|
+
resource_class_resolver: method(:default_resource_class_resolver),
|
|
130
|
+
index_tsim_only_threshold: 1000,
|
|
131
|
+
auto_cast_iso8601_as_datetime: true
|
|
122
132
|
}
|
|
123
133
|
end
|
|
124
134
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: valkyrie
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Trey Pendragon
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-12-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dry-struct
|
|
@@ -452,10 +452,9 @@ files:
|
|
|
452
452
|
- db/migrate/20180212092225_create_updated_at_index.rb
|
|
453
453
|
- db/migrate/20180802220739_add_optimistic_locking_to_orm_resources.rb
|
|
454
454
|
- db/schema.rb
|
|
455
|
-
- gemfiles/activerecord_5_2.gemfile
|
|
456
|
-
- gemfiles/activerecord_6_0.gemfile
|
|
457
455
|
- gemfiles/activerecord_7_0.gemfile
|
|
458
|
-
- gemfiles/
|
|
456
|
+
- gemfiles/activerecord_7_1.gemfile
|
|
457
|
+
- gemfiles/activerecord_7_2.gemfile
|
|
459
458
|
- gemfiles/faraday_1.gemfile
|
|
460
459
|
- lib/valkyrie.rb
|
|
461
460
|
- lib/valkyrie/adapter_container.rb
|
|
@@ -582,7 +581,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
582
581
|
- !ruby/object:Gem::Version
|
|
583
582
|
version: '0'
|
|
584
583
|
requirements: []
|
|
585
|
-
rubygems_version: 3.
|
|
584
|
+
rubygems_version: 3.5.16
|
|
586
585
|
signing_key:
|
|
587
586
|
specification_version: 4
|
|
588
587
|
summary: An ORM using the Data Mapper pattern, specifically built to solve Digital
|
data/gemfiles/faraday_0.gemfile
DELETED