valkyrie 3.3.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bd57af32d07a78e2ac9a9a1c6217b8b601018413c1a08a67762565f92da91cd
4
- data.tar.gz: 58e0073f9ef70694e77d016cf08869d90b920f2fca3a7c42e7141289a8b7121d
3
+ metadata.gz: 7ba113a4df1fa120076006223d629be9d186f96736fbb363781bc78f6c038013
4
+ data.tar.gz: 89e485a082def7836f884354b136c081496b5a9f36e98c2f9f31127dc053ab28
5
5
  SHA512:
6
- metadata.gz: 939dbb151e2cb770e9bfbac0cedbfc78a160ace0f3f1c482560659f1a6cd16ad0984ae1eb15caf49d4ef5926f3a01721e032f7c8363ea815e935064eb547f7c0
7
- data.tar.gz: d2b295e1881cc0d8d45e1c69e6255fab7b5be4d3e277d3e01eaa53498ca7346131ac1c2180d73f675c93b9b4a03d73316b9f6a8256b6b40a7492dda8c088d16a
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: "2.7.7"
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.4.0
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/activerecord_7_0.gemfile"
100
- ruby: 3.2.0
101
- name: "Ruby3-2_rails7-0"
99
+ gemfile: "gemfiles/activerecord_7_2.gemfile"
100
+ ruby: 3.3.5
101
+ name: "Ruby3-3_rails7-2"
102
102
  - build:
103
- gemfile: "gemfiles/activerecord_6_0.gemfile"
104
- ruby: 3.2.0
105
- name: "Ruby3-2_Rails6-0"
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.1.3
109
- name: "Ruby3-1_rails7-0"
108
+ ruby: 3.3.5
109
+ name: "Ruby3-3_rails7-0"
110
110
  - build:
111
- gemfile: "gemfiles/activerecord_6_0.gemfile"
112
- ruby: 3.1.3
113
- name: "Ruby3-1_Rails6-0"
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.0.5
117
- name: "Ruby3-0_rails7-0"
120
+ ruby: 3.2.5
121
+ name: "Ruby3-2_rails7-0"
118
122
  - build:
119
- gemfile: "gemfiles/activerecord_6_0.gemfile"
120
- ruby: 3.0.5
121
- name: "Ruby3-0_Rails6-0"
123
+ gemfile: "gemfiles/activerecord_7_2.gemfile"
124
+ ruby: 3.1.6
125
+ name: "Ruby3-1_rails7-2"
122
126
  - build:
123
- gemfile: "gemfiles/activerecord_7_0.gemfile"
124
- ruby: 2.7.7
125
- name: "Ruby2-7_rails7-0"
127
+ gemfile: "gemfiles/activerecord_7_1.gemfile"
128
+ ruby: 3.1.6
129
+ name: "Ruby3-1_rails7-1"
126
130
  - build:
127
- gemfile: "gemfiles/activerecord_6_0.gemfile"
128
- ruby: 2.7.7
129
- name: "Ruby2-7_Rails6-0"
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: 2.7.7
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/activerecord_7_0.gemfile"
162
- ruby: 3.2.0
163
- name: "Ruby3-2_rails7-0"
149
+ gemfile: "gemfiles/activerecord_7_2.gemfile"
150
+ ruby: 3.3.5
151
+ name: "Ruby3-3_rails7-2"
164
152
  - build:
165
- gemfile: "gemfiles/activerecord_6_0.gemfile"
166
- ruby: 3.2.0
167
- name: "Ruby3-2_Rails6-0"
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.1.3
171
- name: "Ruby3-1_rails7-0"
158
+ ruby: 3.3.5
159
+ name: "Ruby3-3_rails7-0"
172
160
  - build:
173
- gemfile: "gemfiles/activerecord_6_0.gemfile"
174
- ruby: 3.1.3
175
- name: "Ruby3-1_Rails6-0"
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.0.5
179
- name: "Ruby3-0_rails7-0"
170
+ ruby: 3.2.5
171
+ name: "Ruby3-2_rails7-0"
180
172
  - build:
181
- gemfile: "gemfiles/activerecord_6_0.gemfile"
182
- ruby: 3.0.5
183
- name: "Ruby3-0_Rails6-0"
173
+ gemfile: "gemfiles/activerecord_7_2.gemfile"
174
+ ruby: 3.1.6
175
+ name: "Ruby3-1_rails7-2"
184
176
  - build:
185
- gemfile: "gemfiles/activerecord_7_0.gemfile"
186
- ruby: 2.7.7
187
- name: "Ruby2-7_rails7-0"
177
+ gemfile: "gemfiles/activerecord_7_1.gemfile"
178
+ ruby: 3.1.6
179
+ name: "Ruby3-1_rails7-1"
188
180
  - build:
189
- gemfile: "gemfiles/activerecord_6_0.gemfile"
190
- ruby: 2.7.7
191
- name: "Ruby2-7_Rails6-0"
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: 2.7.7
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
@@ -51,7 +51,7 @@ services:
51
51
  volumes:
52
52
  fedora6:
53
53
  services:
54
- image: fcrepo/fcrepo:6.4.0
54
+ image: fcrepo/fcrepo:6.5.1-RC3-tomcat9
55
55
  command:
56
56
  - "catalina.sh"
57
57
  - "run"
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 2.7.5
1
+ ruby 3.3.5
data/Appraisals CHANGED
@@ -1,23 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise "activerecord-7-0" do
4
- gem "activerecord", "~> 7.0.0"
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-5-2" do
12
- gem "activerecord", "~> 5.2.0"
7
+ appraise "activerecord-7-1" do
8
+ gem "activerecord", "~> 7.1.0"
13
9
  end
14
10
 
15
- appraise "faraday-0" do
16
- gem "faraday", "< 1"
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", "~> 6.0.0"
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
- else
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
@@ -3,7 +3,7 @@
3
3
 
4
4
  source "https://rubygems.org"
5
5
 
6
- gem "activerecord", "~> 5.2.0"
6
+ gem "activerecord", "~> 7.1.0"
7
7
  gem "ldp"
8
8
  gem "pg"
9
9
  gem "rsolr"
@@ -3,7 +3,7 @@
3
3
 
4
4
  source "https://rubygems.org"
5
5
 
6
- gem "activerecord", "~> 6.0.0"
6
+ gem "activerecord", "~> 7.2.0"
7
7
  gem "ldp"
8
8
  gem "pg"
9
9
  gem "rsolr"
@@ -3,7 +3,7 @@
3
3
 
4
4
  source "https://rubygems.org"
5
5
 
6
- gem "activerecord", "~> 6.0.0"
6
+ gem "activerecord", "~> 7.0.0"
7
7
  gem "ldp"
8
8
  gem "pg"
9
9
  gem "rsolr"
@@ -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.object.to_s.start_with?("http://www.w3.org/ns/ldp", "http://fedora.info")
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
- [5, 6].include?(adapter.fedora_version) ? "http://fedora.info/definitions/fcrepo#PreferInboundReferences" : ::RDF::Vocab::Fcrepo4.InboundReferences
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 > 1000
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
- expect(uploaded_file = storage_adapter.upload(file: file, original_filename: 'foo.jpg', resource: resource, fake_upload_argument: true)).to be_kind_of Valkyrie::StorageAdapter::File
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
- expect(storage_adapter.find_versions(id: uploaded_file.id).length).to eq 1
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 + 2
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
- expect(storage_adapter.find_versions(id: new_version.id).length).to eq 0
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("disk://#{new_path}"))
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?("disk://#{base_path}")
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(/^disk:\/\//, '')
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?(PROTOCOL)
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(/^.+\/\//, PROTOCOL)), version_id: version_id)
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(/^.+\/\//, PROTOCOL)), version_id: version_id)
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
- end
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(PROTOCOL, "#{connection.http.scheme}://")
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://", PROTOCOL)
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("memory://#{resource.id}")
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?("memory://")
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("versiondisk://#{new_path}"))
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("versiondisk://#{new_path}"))
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?("versiondisk://#{base_path}")
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("versiondisk://#{file}"))
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(/^versiondisk:\/\//, '')
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(/^versiondisk:\/\//, '')
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("versiondisk://#{file}"))
159
+ VersionId.new(Valkyrie::ID.new("#{protocol}#{file}"))
149
160
  end
150
161
  end
151
162
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Valkyrie
3
- VERSION = "3.3.0"
3
+ VERSION = "3.5.0"
4
4
  end
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.3.0
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-07-08 00:00:00.000000000 Z
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/faraday_0.gemfile
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.1.6
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
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
- # This file was generated by Appraisal
3
-
4
- source "https://rubygems.org"
5
-
6
- gem "activerecord", "~> 6.0.0"
7
- gem "ldp"
8
- gem "pg"
9
- gem "rsolr"
10
- gem "faraday", "< 1"
11
-
12
- gemspec path: "../"