class ActiveFedora::Indexing::FieldMapper
Public Instance Methods
@api @params [Hash] doc the hash to insert the value into @params [String] name the name of the field (without the suffix) @params [String,Date] value the value to be inserted @params [Array,Hash] indexer_args the arguments that find the indexer @returns [Hash] doc the document that was provided with the new field (replacing any field with the same name)
# File lib/active_fedora/indexing/field_mapper.rb, line 15 def set_field(doc, name, value, *indexer_args) # adding defaults indexer indexer_args = [:stored_searchable] if indexer_args.empty? doc.merge! solr_names_and_values(name, value, indexer_args) doc end
@api Given a field name, index_type, etc., returns the corresponding Solr name. TODO field type is the input format, maybe we could just detect that? See github.com/samvera/active_fedora/issues/1338 @param [String] field_name the ruby (term) name which will get a suffix appended to become a Solr field name @param opts - index_type is only needed if the FieldDescriptor requires it (e.g. :searcahble) @return [String] name of the solr field, based on the params
# File lib/active_fedora/indexing/field_mapper.rb, line 29 def solr_name(field_name, *opts) index_type, args = if opts.first.is_a? Hash [:stored_searchable, opts.first] elsif opts.empty? [:stored_searchable, { type: :text }] else [opts[0], opts[1] || { type: :string }] end indexer(index_type).name_and_converter(field_name, args).first end
Given a field name-value pair, a data type, and an array of index types, returns a hash of mapped names and values. The values in the hash are arrays, and may contain multiple values.
# File lib/active_fedora/indexing/field_mapper.rb, line 43 def solr_names_and_values(field_name, field_value, index_types) return {} if field_value.nil? # Determine the set of index types index_types = Array(index_types) index_types.uniq! index_types.dup.each do |index_type| if index_type.to_s =~ /^not_(.*)/ index_types.delete index_type # not_foo index_types.delete Regexp.last_match(1).to_sym # foo end end # Map names and values results = {} # Time seems to extend enumerable, so wrap it so we don't interate over each of its elements. field_value = [field_value] if field_value.is_a? Time index_types.each do |index_type| Array(field_value).each do |single_value| # Get mapping for field descriptor = indexer(index_type) data_type = extract_type(single_value) name, converter = descriptor.name_and_converter(field_name, type: data_type) next unless name # Is there a custom converter? # TODO instead of a custom converter, look for input data type and output data type. Create a few methods that can do that cast. # See https://github.com/samvera/active_fedora/issues/1339 value = if converter if converter.arity == 1 converter.call(single_value) else converter.call(single_value, field_name) end elsif data_type == :boolean single_value else single_value.to_s end # Add mapped name & value, unless it's a duplicate if descriptor.evaluate_suffix(data_type).multivalued? values = (results[name] ||= []) values << value unless value.nil? || values.include?(value) else Rails.logger.warn "Setting #{name} to `#{value}', but it already had `#{results[name]}'" if results[name] results[name] = value end end end results end
Private Instance Methods
# File lib/active_fedora/indexing/field_mapper.rb, line 130 def extract_type(value) case value when NilClass nil when Integer # In ruby < 2.4, Fixnum extends Integer :integer when DateTime :time when TrueClass, FalseClass :boolean else value.class.to_s.underscore.to_sym end end
@param index_type [Symbol] search through the descriptors (class attribute) until a module is found that responds to index_type, then call it.
# File lib/active_fedora/indexing/field_mapper.rb, line 123 def index_type_macro(index_type) klass = self.class.descriptors.find { |descriptor_klass| descriptor_klass.respond_to? index_type } raise UnknownIndexMacro, "Unable to find `#{index_type}' in #{self.class.descriptors}" unless klass klass.send(index_type) end
@param [Symbol, String, Descriptor] index_type is a Descriptor
, a symbol that references a method that returns a Descriptor
, or a string which will be used as the suffix. @return [Descriptor]
# File lib/active_fedora/indexing/field_mapper.rb, line 105 def indexer(index_type) index_type = case index_type when Symbol index_type_macro(index_type) when String StringDescriptor.new(index_type) when Descriptor index_type else raise InvalidIndexDescriptor, "#{index_type.class} is not a valid indexer_type. Use a String, Symbol or Descriptor." end raise InvalidIndexDescriptor, "index type should be an Descriptor, you passed: #{index_type.class}" unless index_type.is_a? Descriptor index_type end