sul-dlss/dor-services-app

View on GitHub
app/services/indexing/builders/name_builder.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
# frozen_string_literal: true

module Indexing
  module Builders
    # class methods return the name values to go in Solr document fields
    #   used for both contributors and for topics
    class NameBuilder
      # @param [Symbol] strategy ":first" is the strategy for how to choose a name if primary and display name is not found
      # @return [Array<String>] names
      def self.build_all(cocina_contributors)
        flat_names = cocina_contributors.filter_map { |cocina_contributor| flat_names_for(cocina_contributor) }.flatten
        flat_names.filter_map { |name| build_name(name) }
      end

      # @param [Symbol] strategy ":first" is the strategy for how to choose a name if primary and display name is not found
      # @return [String] name
      def self.build_primary_name(names, strategy: :first)
        names = Array(names) unless names.is_a?(Array)
        flat_names = flat_names_for(names)
        name = display_name_for(flat_names) || primary_name_for(flat_names)
        name ||= flat_names.first if strategy == :first
        return build_name(name) if name

        flat_names.filter_map { |one| build_name(one) }.first
      end

      def self.build_name(name)
        if name.groupedValue.present?
          name.groupedValue.find { |grouped_value| grouped_value.type == 'name' }&.value
        elsif name.structuredValue.present?
          name_part = joined_name_parts(name, 'name', '. ').presence
          surname = joined_name_parts(name, 'surname', ' ')
          forename = joined_name_parts(name, 'forename', ' ')
          terms_of_address = joined_name_parts(name, 'term of address', ', ')
          life_dates = joined_name_parts(name, 'life dates', ', ')
          activity_dates = joined_name_parts(name, 'activity dates', ', ')
          joined_name = name_part || join_parts([surname, forename], ', ')
          joined_name = join_parts([joined_name, terms_of_address], ' ')
          joined_name = join_parts([joined_name, life_dates], ', ')
          join_parts([joined_name, activity_dates], ', ')
        else
          name.value
        end
      end

      def self.display_name_for(names)
        names.find { |name| name.type == 'display' }
      end

      def self.primary_name_for(names)
        names.find { |name| name.status == 'primary' }
      end

      def self.flat_names_for(names)
        names.flat_map { |name| name.parallelValue.presence || name }
      end

      def self.joined_name_parts(name, type, joiner)
        join_parts(name.structuredValue.select { |structured_value| structured_value.type == type }.map(&:value), joiner)
      end

      def self.join_parts(parts, joiner)
        parts.compact_blank.join(joiner)
      end
    end
  end
end