active-fedora 11.5.6 → 12.0.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 (47) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +4 -0
  3. data/.travis.yml +15 -0
  4. data/Gemfile +1 -3
  5. data/README.md +10 -13
  6. data/active-fedora.gemspec +7 -9
  7. data/lib/active_fedora.rb +3 -5
  8. data/lib/active_fedora/associations/collection_proxy.rb +0 -2
  9. data/lib/active_fedora/attributes/property_builder.rb +3 -1
  10. data/lib/active_fedora/caching_connection.rb +1 -1
  11. data/lib/active_fedora/errors.rb +4 -0
  12. data/lib/active_fedora/fedora.rb +5 -0
  13. data/lib/active_fedora/file.rb +3 -1
  14. data/lib/active_fedora/file/attributes.rb +5 -0
  15. data/lib/active_fedora/file_io.rb +120 -0
  16. data/lib/active_fedora/indexing.rb +6 -1
  17. data/lib/active_fedora/indexing/default_descriptors.rb +128 -0
  18. data/lib/active_fedora/indexing/descendant_fetcher.rb +22 -18
  19. data/lib/active_fedora/indexing/descriptor.rb +44 -0
  20. data/lib/active_fedora/indexing/field_mapper.rb +146 -0
  21. data/lib/active_fedora/indexing/inserter.rb +40 -0
  22. data/lib/active_fedora/indexing/suffix.rb +81 -0
  23. data/lib/active_fedora/indexing_service.rb +2 -2
  24. data/lib/active_fedora/ldp_resource.rb +1 -2
  25. data/lib/active_fedora/railtie.rb +0 -1
  26. data/lib/active_fedora/rdf/field_map_entry.rb +2 -2
  27. data/lib/active_fedora/rdf/indexing_service.rb +6 -6
  28. data/lib/active_fedora/relation.rb +0 -14
  29. data/lib/active_fedora/relation/delegation.rb +1 -2
  30. data/lib/active_fedora/relation/finder_methods.rb +19 -39
  31. data/lib/active_fedora/version.rb +1 -1
  32. data/lib/generators/active_fedora/config/fedora/templates/.fcrepo_wrapper +1 -1
  33. data/lib/generators/active_fedora/config/solr/templates/solr.yml +3 -3
  34. data/lib/generators/active_fedora/config/solr/templates/solr/config/schema.xml +34 -33
  35. data/spec/integration/base_spec.rb +39 -35
  36. data/spec/integration/indexing/descendant_fetcher_spec.rb +64 -0
  37. data/spec/integration/relation_spec.rb +1 -39
  38. data/spec/integration/scoping_spec.rb +17 -11
  39. data/spec/spec_helper.rb +1 -1
  40. data/spec/unit/active_fedora/indexing/inserter_spec.rb +30 -0
  41. data/spec/unit/attributes_spec.rb +3 -7
  42. data/spec/unit/fedora_spec.rb +12 -0
  43. data/spec/unit/file_configurator_spec.rb +0 -9
  44. data/spec/unit/file_io_spec.rb +137 -0
  45. data/spec/unit/file_spec.rb +14 -17
  46. metadata +26 -30
  47. data/.circleci/config.yml +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 419ffa1beafe8db1f095d978f5bf68bbc6d9ca821e2f207df12de4eb82a78662
4
- data.tar.gz: '018d793df4de36dd4a207ca6b70af4474d7996acf6a12ec7acac19e019e63ef0'
2
+ SHA1:
3
+ metadata.gz: bedac14828094879a2772f8ab082a5ff0af2ac44
4
+ data.tar.gz: efd5b61d006fd8a7f2c99105d7cd11bf00b7c5b8
5
5
  SHA512:
6
- metadata.gz: a5cf6e6c08b021586dbb3a282d2bb91d128a5578e947725c365a239807814f50c4d87067f6e79e68215a9c1870a48b2d41021af51ba7ed65b9778118ce003663
7
- data.tar.gz: 90883925eaaf6601f24cefa301cccb40529b0034100ccf51e92a4da2fbdfa017a405289fb620c5e1352aaa177d9c37c984f5b50dd72bc66ef4ff6024fe7eeb02
6
+ metadata.gz: e56690ae20fd41c22ef507fc89a8c2350ac956cded3bd72d7d46ff43e181ccfe9224e3e40535ab5716b64a34efea98d87bbd7d364fa14c5b9f879cacf65be99f
7
+ data.tar.gz: 18ccc767a70af04dff33580ef2785483adbc3f0e51d8ae382ab65cf49db741b9cca8042c1cf7c59613aa6bcdbe4a0f91839a9a55b6d786c3b08dc74c2bd7f67c
@@ -50,6 +50,8 @@ Metrics/CyclomaticComplexity:
50
50
  - 'lib/active_fedora/file.rb'
51
51
  - 'lib/active_fedora/attribute_methods.rb'
52
52
  - 'lib/active_fedora/scoping/named.rb'
53
+ - 'lib/active_fedora/indexing/field_mapper.rb'
54
+ - 'lib/active_fedora/indexing/suffix.rb'
53
55
  - 'lib/active_fedora/inheritance.rb'
54
56
 
55
57
  Metrics/PerceivedComplexity:
@@ -66,6 +68,7 @@ Metrics/PerceivedComplexity:
66
68
  - 'lib/active_fedora/associations/collection_association.rb'
67
69
  - 'lib/active_fedora/attribute_methods.rb'
68
70
  - 'lib/active_fedora/scoping/named.rb'
71
+ - 'lib/active_fedora/indexing/field_mapper.rb'
69
72
  - 'lib/active_fedora/inheritance.rb'
70
73
 
71
74
  Metrics/ModuleLength:
@@ -127,6 +130,7 @@ Style/PredicateName:
127
130
  - 'lib/active_fedora/association_hash.rb'
128
131
  - 'lib/active_fedora/aggregation/list_source.rb'
129
132
  - 'lib/active_fedora/associations/builder/aggregation.rb'
133
+ - 'lib/active_fedora/indexing/suffix.rb'
130
134
 
131
135
  Style/GuardClause:
132
136
  Exclude:
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ cache: bundler
3
+ sudo: false
4
+ rvm: 2.4.1
5
+ matrix:
6
+ include:
7
+ - rvm: 2.3.4
8
+ env: "RAILS_VERSION=4.2.8"
9
+ - env: "RAILS_VERSION=5.1.1"
10
+ global_env:
11
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
12
+ before_install:
13
+ - gem update --system
14
+ before_script:
15
+ - jdk_switcher use oraclejdk8
data/Gemfile CHANGED
@@ -4,16 +4,14 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec path: File.expand_path('..', __FILE__)
6
6
 
7
- gem 'byebug' unless ENV['CI']
7
+ gem 'byebug' unless ENV['TRAVIS']
8
8
  gem 'pry-byebug' unless ENV['CI']
9
9
 
10
10
  gem 'activemodel', ENV['RAILS_VERSION'] if ENV['RAILS_VERSION']
11
- gem 'rsolr', ENV['RSOLR_VERSION'] if ENV['RSOLR_VERSION']
12
11
 
13
12
  group :test do
14
13
  gem 'simplecov', require: false
15
14
  gem 'coveralls', require: false
16
- gem 'rspec_junit_formatter'
17
15
  end
18
16
 
19
17
  gem 'jruby-openssl', platform: :jruby
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  Description
2
2
  -----------
3
3
 
4
- [![Build Status](https://travis-ci.org/projecthydra/active_fedora.png?branch=master)](https://travis-ci.org/projecthydra/active\_fedora)
4
+ [![Build Status](https://travis-ci.org/samvera/active_fedora.png?branch=master)](https://travis-ci.org/samvera/active\_fedora)
5
5
  [![Version](https://badge.fury.io/rb/active-fedora.png)](http://badge.fury.io/rb/active-fedora)
6
- [![Dependencies](https://gemnasium.com/projecthydra/active_fedora.png)](https://gemnasium.com/projecthydra/active\_fedora)
7
- [![Coverage Status](https://img.shields.io/coveralls/projecthydra/active_fedora.svg)](https://coveralls.io/r/projecthydra/active_fedora)
6
+ [![Dependencies](https://gemnasium.com/samvera/active_fedora.png)](https://gemnasium.com/samvera/active\_fedora)
7
+ [![Coverage Status](https://img.shields.io/coveralls/samvera/active_fedora.svg)](https://coveralls.io/r/samvera/active_fedora)
8
8
 
9
9
  ActiveFedora is a Ruby gem for creating and
10
10
  managing objects in the Fedora Repository Architecture
@@ -15,8 +15,8 @@ Getting Help
15
15
  ------------
16
16
 
17
17
  - Community Discussions & Mailing List are located at
18
- [http://groups.google.com/group/hydra-tech](http://groups.google.com/group/hydra-tech)
19
- - Developers hang out on IRC in \#projecthydra on freenet.
18
+ [http://groups.google.com/group/samvera-tech](http://groups.google.com/group/samvera-tech)
19
+ - Developers hang out on [slack.samvera.org](http://slack.samvera.org/)
20
20
 
21
21
  Installation
22
22
  ------------
@@ -30,7 +30,7 @@ gem install active-fedora
30
30
  Getting Started
31
31
  ---------------
32
32
 
33
- The [Dive into Hydra](https://github.com/projecthydra/hydra/wiki/Dive-into-Hydra)
33
+ The [Dive into Hydra](https://github.com/samvera/hydra/wiki/Dive-into-Hydra)
34
34
  gives you a brief tour through ActiveFedora’s features on the command line.
35
35
 
36
36
  Generators
@@ -47,21 +47,18 @@ Testing (this Gem)
47
47
 
48
48
  In order to run the RSpec tests, you need to have a copy of the
49
49
  ActiveFedora source code, and then run bundle install in the source
50
- directory. Testing requires hydra-jetty, which contains version for
51
- Fedora and Solr. Setting up and maintaining hydra-jetty for the purposes
52
- of testing this gem is all accomplished via:
50
+ directory. You can download the source code by doing the following:
53
51
 
54
52
  ```bash
55
- git clone https://github.com/projecthydra/active_fedora.git
56
- cd active_fedora # or whatever directory your clone is in
53
+ git clone https://github.com/samvera/active_fedora.git
54
+ cd active_fedora
57
55
  bundle install
58
56
  ```
59
57
 
60
58
  ### Using the continuous integration server
61
59
 
62
60
  You can test ActiveFedora using the same process as our continuous
63
- integration server. To do that, unzip a copy of hydra-jetty first. This includes copies of Fedora and Solr which are
64
- used during the testing process.
61
+ integration server. This will automatically pull down a copy of Solr and Fedora Content Repository.
65
62
 
66
63
  The `ci` rake task will download solr and fedora, start them,
67
64
  and run the tests for you.
@@ -7,32 +7,31 @@ Gem::Specification.new do |s|
7
7
  s.version = ActiveFedora::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Matt Zumwalt", "McClain Looney", "Justin Coyne"]
10
- s.email = ["matt.zumwalt@yourmediashelf.com"]
10
+ s.email = ["samvera-tech@googlegroups.com"]
11
11
  s.homepage = %q{https://github.com/projecthydra/active_fedora}
12
12
  s.summary = %q{A convenience libary for manipulating documents in the Fedora Repository.}
13
13
  s.description = %q{ActiveFedora provides for creating and managing objects in the Fedora Repository Architecture.}
14
- s.license = "APACHE2"
14
+ s.license = "Apache-2.0"
15
15
  s.required_ruby_version = '~> 2.0'
16
16
 
17
17
  s.add_dependency 'rsolr', '>= 1.1.2', '< 3'
18
18
  s.add_dependency 'solrizer', '>= 3.4', '< 5'
19
- s.add_dependency "activesupport", '>= 4.2.4', '< 5.2'
20
- s.add_dependency "activemodel", '>= 4.2', '< 5.2'
19
+ s.add_dependency "activesupport", '>= 4.2.4', '< 6'
20
+ s.add_dependency "activemodel", '>= 4.2', '< 6'
21
21
  s.add_dependency "active-triples", '>= 0.11.0', '< 2.0.0'
22
22
  s.add_dependency "deprecation"
23
23
  s.add_dependency "ldp", '~> 0.7.0'
24
- s.add_dependency 'rdf-vocab', '< 3.1.5'
25
24
  s.add_dependency "ruby-progressbar", '~> 1.0'
26
25
  s.add_dependency 'faraday', '~> 0.12.1'
27
26
  s.add_dependency 'faraday-encoding', '0.0.4'
28
27
 
29
- s.add_development_dependency "rails", ">= 4.2"
28
+ s.add_development_dependency "rails"
30
29
  s.add_development_dependency "rdoc"
31
30
  s.add_development_dependency "yard"
32
31
  s.add_development_dependency "rake"
33
- s.add_development_dependency "solr_wrapper", "~> 2.0"
32
+ s.add_development_dependency "solr_wrapper", "~> 1.0"
34
33
  s.add_development_dependency 'fcrepo_wrapper', '~> 0.2'
35
- s.add_development_dependency "rspec", "~> 3.0"
34
+ s.add_development_dependency "rspec", "~> 3.5"
36
35
  s.add_development_dependency "rspec-its"
37
36
  s.add_development_dependency "equivalent-xml"
38
37
  s.add_development_dependency "simplecov", '~> 0.8'
@@ -47,5 +46,4 @@ Gem::Specification.new do |s|
47
46
  "README.md"
48
47
  ]
49
48
  s.require_paths = ["lib"]
50
-
51
49
  end
@@ -1,7 +1,6 @@
1
1
  require 'active_support'
2
2
  require 'active_model'
3
3
  require 'ldp'
4
- require 'solrizer'
5
4
  require 'active_fedora/file_configurator'
6
5
  require 'active_support/core_ext/class/attribute'
7
6
  require 'active_support/core_ext/object'
@@ -68,6 +67,7 @@ module ActiveFedora #:nodoc:
68
67
  autoload :FedoraAttributes
69
68
  autoload :File
70
69
  autoload :FileConfigurator
70
+ autoload :FileIO
71
71
  autoload :FilePathBuilder
72
72
  autoload :FilePersistence
73
73
  autoload :FileRelation
@@ -242,16 +242,14 @@ module ActiveFedora #:nodoc:
242
242
  end
243
243
 
244
244
  def index_field_mapper
245
- Solrizer.default_field_mapper
245
+ @index_field_mapper ||= Indexing::FieldMapper.new
246
246
  end
247
247
 
248
248
  def id_field
249
249
  if defined?(SOLR_DOCUMENT_ID) && !SOLR_DOCUMENT_ID.nil?
250
250
  SOLR_DOCUMENT_ID
251
- elsif defined?(Solrizer)
252
- Solrizer.default_field_mapper.id_field
253
251
  else
254
- 'id'.freeze
252
+ ActiveFedora.index_field_mapper.id_field
255
253
  end
256
254
  end
257
255
 
@@ -41,8 +41,6 @@ module ActiveFedora
41
41
  merge! association.scope(nullify: false)
42
42
  end
43
43
 
44
- delegate :each, to: :to_a
45
-
46
44
  def target
47
45
  @association.target
48
46
  end
@@ -13,9 +13,10 @@ module ActiveFedora::Attributes
13
13
  end
14
14
 
15
15
  def self.define_writers(mixin, name)
16
+ # RDF Terms are singular, even if they respond to `#each`
16
17
  mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
17
18
  def #{name}=(value)
18
- if value.present? && !value.respond_to?(:each)
19
+ unless value.nil? || (value.respond_to?(:each) && !(value.respond_to?(:term?) && value.term?))
19
20
  raise ArgumentError, "You attempted to set the property `#{name}' of \#{id} to a scalar value. However, this property is declared as being multivalued."
20
21
  end
21
22
  set_value(:#{name}, value)
@@ -43,6 +44,7 @@ module ActiveFedora::Attributes
43
44
  end
44
45
 
45
46
  def self.define_singular_writers(mixin, name)
47
+ # RDF Terms are singular, even if they respond to `#each`
46
48
  mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
47
49
  def #{name}=(value)
48
50
  if value.respond_to?(:each) && !(value.respond_to?(:term?) && value.term?)
@@ -10,7 +10,7 @@ module ActiveFedora
10
10
  if @cache_enabled
11
11
  cache_resource(url) { super }
12
12
  else
13
- super
13
+ log(url) { super }
14
14
  end
15
15
  end
16
16
 
@@ -40,6 +40,10 @@ module ActiveFedora #:nodoc:
40
40
  class AssociationNotFoundError < ConfigurationError #:nodoc:
41
41
  end
42
42
 
43
+ # Raised when an object is loaded from Fedora by an incompatible class
44
+ class ModelMismatch < ActiveFedoraError
45
+ end
46
+
43
47
  # This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations
44
48
  # (has_many, has_one) when there is at least 1 child associated instance.
45
49
  # ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
@@ -49,6 +49,10 @@ module ActiveFedora
49
49
  @config[:ssl]
50
50
  end
51
51
 
52
+ def request_options
53
+ @config[:request]
54
+ end
55
+
52
56
  def connection
53
57
  @connection ||= begin
54
58
  build_connection
@@ -86,6 +90,7 @@ module ActiveFedora
86
90
  def authorized_connection
87
91
  options = {}
88
92
  options[:ssl] = ssl_options if ssl_options
93
+ options[:request] = request_options if request_options
89
94
  Faraday.new(host, options) do |conn|
90
95
  conn.response :encoding # use Faraday::Encoding middleware
91
96
  conn.adapter Faraday.default_adapter # net/http
@@ -196,7 +196,9 @@ module ActiveFedora
196
196
  end
197
197
 
198
198
  def local_or_remote_content(ensure_fetch = true)
199
- @content ||= ensure_fetch ? remote_content : @ds_content unless new_record?
199
+ return @content if new_record?
200
+
201
+ @content ||= ensure_fetch ? remote_content : @ds_content
200
202
  @content.rewind if behaves_like_io?(@content)
201
203
  @content
202
204
  end
@@ -49,6 +49,11 @@ module ActiveFedora::File::Attributes
49
49
  created && created.first
50
50
  end
51
51
 
52
+ def modified_date
53
+ modified = metadata.attributes["http://fedora.info/definitions/v4/repository#lastModified"]
54
+ modified && modified.first
55
+ end
56
+
52
57
  private
53
58
 
54
59
  # Fcrepo4.digest was used by Fedora < 4.3, but it was removed
@@ -0,0 +1,120 @@
1
+ module ActiveFedora
2
+ ##
3
+ # IO like object for reading Fedora files.
4
+ # Use ActiveFedora::FileIO.new(fedora_file) to create one. You can then call
5
+ # read on it or use it with IO.copy_stream and the like.
6
+ #
7
+ # @Note The stream will always be in binmode and return ASCII-8BIT content.
8
+ class FileIO
9
+ attr_reader :pos
10
+
11
+ ##
12
+ # @param [ActiveFedora::File] the file which is wrapped in this IO object.
13
+ def initialize(fedora_file)
14
+ @fedora_file = fedora_file
15
+ @closed = false
16
+ rewind # this initialises various variables
17
+ end
18
+
19
+ def size
20
+ @fedora_file.size
21
+ end
22
+
23
+ alias length size
24
+
25
+ def binmode
26
+ # Do nothing, just return self. The stream is essentially always in binmode.
27
+ self
28
+ end
29
+
30
+ def binmode?
31
+ true
32
+ end
33
+
34
+ ##
35
+ # Read bytes from the file. See IO.read for more information.
36
+ # @param [Integer] the number of bytes to read. If nil or omitted, the
37
+ # entire contents will be read.
38
+ # @param [String] a string in which the contents are read. Can be omitted.
39
+ # @return [String] the read bytes. If number of bytes to read was not
40
+ # specified then always returns a String, possibly an empty
41
+ # one. If number of bytes was specified then the returned
42
+ # string will always be at least one byte long. If no bytes
43
+ # are left in the file returns nil instead.
44
+ def read(amount = nil, buf = nil)
45
+ raise(IOError, "closed stream") if @closed
46
+
47
+ buf ||= ''.force_encoding("ASCII-8BIT")
48
+ buf.clear
49
+
50
+ if amount.nil?
51
+ read_to_buf(nil, buf) # read the entire file, returns buf
52
+ elsif amount < 0
53
+ raise(ArgumentError, "negative length #{amount} given")
54
+ elsif amount.zero?
55
+ ''
56
+ else
57
+ read_to_buf(amount, buf)
58
+ # if amount was specified but we reached eof before reading anything
59
+ # then we must return nil
60
+ buf.empty? ? nil : buf
61
+ end
62
+ end
63
+
64
+ ##
65
+ # Rewinds the io object to the beginning. Read will return bytes from the
66
+ # start of the file again.
67
+ def rewind
68
+ raise(IOError, "closed stream") if @closed
69
+ @pos = 0
70
+ @buffer = nil
71
+ @stream_fiber = Fiber.new do
72
+ @fedora_file.stream.each do |chunk|
73
+ Fiber.yield chunk
74
+ end
75
+ @stream_fiber = nil
76
+ # last value from Fiber is the return value of the block which should be nil
77
+ end
78
+ 0
79
+ end
80
+
81
+ ##
82
+ # Closes the file. No further action can be taken on the file.
83
+ def close
84
+ @closed = true
85
+ @stream_fiber = nil
86
+ nil
87
+ end
88
+
89
+ private
90
+
91
+ def read_to_buf(amount, buf)
92
+ while (amount.nil? || buf.length < amount) && fill_buffer
93
+ buf << consume_buffer(amount.nil? ? nil : (amount - buf.length))
94
+ end
95
+ buf
96
+ end
97
+
98
+ def consume_buffer(count = nil)
99
+ if count.nil? || count >= @buffer.length
100
+ @pos += @buffer.length
101
+ @buffer .tap do
102
+ @buffer = nil
103
+ end
104
+ else
105
+ @buffer.slice!(0, count) .tap do |slice|
106
+ @pos += slice.length
107
+ end
108
+ end
109
+ end
110
+
111
+ def fill_buffer
112
+ return true if @buffer.present?
113
+ # Ruby Net library doesn't seem to like it if we modify the returned
114
+ # chunk in any way, hence dup.
115
+ @buffer = @stream_fiber.try(:resume).try(:dup)
116
+ @buffer.try(:force_encoding, 'ASCII-8BIT')
117
+ !@buffer.nil?
118
+ end
119
+ end
120
+ end
@@ -12,8 +12,13 @@ module ActiveFedora
12
12
  extend ActiveSupport::Autoload
13
13
 
14
14
  eager_autoload do
15
- autoload :Map
15
+ autoload :DefaultDescriptors
16
+ autoload :Descriptor
16
17
  autoload :DescendantFetcher
18
+ autoload :FieldMapper
19
+ autoload :Inserter
20
+ autoload :Map
21
+ autoload :Suffix
17
22
  end
18
23
 
19
24
  included do
@@ -0,0 +1,128 @@
1
+ module ActiveFedora
2
+ module Indexing
3
+ class DefaultDescriptors
4
+ # The suffix produced depends on the type parameter -- produces suffixes:
5
+ # _tesim - for strings or text fields
6
+ # _dtsim - for dates
7
+ # _isim - for integers
8
+ def self.stored_searchable
9
+ @stored_searchable ||= Descriptor.new(stored_searchable_field_definition, converter: searchable_converter, requires_type: true)
10
+ end
11
+
12
+ # The suffix produced depends on the type parameter -- produces suffixes:
13
+ # _teim - for strings or text fields
14
+ # _dtim - for dates
15
+ # _iim - for integers
16
+ def self.searchable
17
+ @searchable ||= Descriptor.new(searchable_field_definition, converter: searchable_converter, requires_type: true)
18
+ end
19
+
20
+ # Takes fields which are stored as strings, but we want indexed as dates. (e.g. "November 6th, 2012")
21
+ # produces suffixes:
22
+ # _dtsim - for dates
23
+ def self.dateable
24
+ @dateable ||= Descriptor.new(:date, :stored, :indexed, :multivalued, converter: dateable_converter)
25
+ end
26
+
27
+ # Produces _sim suffix
28
+ def self.facetable
29
+ @facetable ||= Descriptor.new(:string, :indexed, :multivalued)
30
+ end
31
+
32
+ # Produces _ssim suffix
33
+ # This is useful for when you only want to match whole words, such as user/group names from the the rightsMetadata datastream
34
+ def self.symbol
35
+ @symbol ||= Descriptor.new(:string, :stored, :indexed, :multivalued)
36
+ end
37
+
38
+ # The suffix produced depends on the type parameter -- produces suffixes:
39
+ # _tei - for text fields
40
+ # _si - for strings
41
+ # _dti - for dates
42
+ # _ii - for integers
43
+ def self.sortable
44
+ @sortable ||= Descriptor.new(sortable_field_definition, converter: searchable_converter, requires_type: true)
45
+ end
46
+
47
+ # Fields that are both stored and sortable
48
+ # Produces _ssi suffix if field_type is string
49
+ # Produces _dtsi suffix if field_type is date
50
+ def self.stored_sortable
51
+ @stored_sortable ||= Descriptor.new(->(field_type) { [field_type, :stored, :indexed] }, converter: searchable_converter)
52
+ end
53
+
54
+ # Produces _ssm suffix
55
+ def self.displayable
56
+ @displayable ||= Descriptor.new(:string, :stored, :multivalued)
57
+ end
58
+
59
+ # Produces _tim suffix (used to be _unstem)
60
+ def self.unstemmed_searchable
61
+ @unstemmed_searchable ||= Descriptor.new(:text, :indexed, :multivalued)
62
+ end
63
+
64
+ def self.simple
65
+ @simple ||= Descriptor.new(->(field_type) { [field_type, :indexed] })
66
+ end
67
+
68
+ class << self
69
+ def searchable_field_definition
70
+ lambda do |type|
71
+ type = :text_en if [:string, :text].include?(type) # for backwards compatibility with old solr schema
72
+ vals = [type, :indexed, :multivalued]
73
+ vals
74
+ end
75
+ end
76
+
77
+ def stored_searchable_field_definition
78
+ lambda do |type|
79
+ type = :text_en if [:string, :text].include?(type) # for backwards compatibility with old solr schema
80
+ if type == :boolean
81
+ [type, :indexed, :stored]
82
+ else
83
+ [type, :indexed, :stored, :multivalued]
84
+ end
85
+ end
86
+ end
87
+
88
+ def sortable_field_definition
89
+ lambda do |type|
90
+ vals = [type, :indexed]
91
+ vals
92
+ end
93
+ end
94
+
95
+ def searchable_converter
96
+ lambda do |type|
97
+ case type
98
+ when :date, :time
99
+ ->(val) { iso8601_date(val) }
100
+ end
101
+ end
102
+ end
103
+
104
+ def dateable_converter
105
+ lambda do |_type|
106
+ lambda do |val|
107
+ begin
108
+ iso8601_date(Date.parse(val))
109
+ rescue ArgumentError
110
+ nil
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ def iso8601_date(value)
117
+ if value.is_a?(Date) || value.is_a?(Time)
118
+ DateTime.parse(value.to_s).to_time.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
119
+ elsif !value.empty?
120
+ DateTime.parse(value).to_time.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
121
+ end
122
+ rescue ArgumentError
123
+ raise ArgumentError, "Unable to parse `#{value}' as a date-time object"
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end