sul-dlss/dor-services-app

View on GitHub
app/services/indexing/indexers/identifiable_indexer.rb

Summary

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

module Indexing
  module Indexers
    # Indexes the druid, metadata sources, and the apo titles
    class IdentifiableIndexer
      attr_reader :cocina, :cocina_finder

      CURRENT_CATALOG_TYPE = 'folio'

      def initialize(cocina:, **)
        @cocina = cocina
      end

      ## Module-level variable, shared between ALL mixin includers (and ALL *their* includers/extenders)!
      ## used for caching apo titles
      @@apo_hash = {} # rubocop:disable Style/ClassVars

      # @return [Hash] the partial solr document for identifiable concerns
      def to_solr
        {}.tap do |solr_doc|
          add_apo_titles(solr_doc, cocina.administrative.hasAdminPolicy)

          solr_doc['metadata_source_ssim'] = identity_metadata_sources unless cocina.is_a? Cocina::Models::AdminPolicyWithMetadata
          solr_doc['druid_prefixed_ssi'] = cocina.externalIdentifier
          solr_doc['druid_bare_ssi'] = cocina.externalIdentifier.delete_prefix('druid:')
        end
      end

      # Clears out the cache of apos. Used primarily in testing.
      def self.reset_cache!
        @@apo_hash = {} # rubocop:disable Style/ClassVars
      end

      private

      # @return [Array<String>] calculated values for Solr index
      def identity_metadata_sources
        return ['DOR'] if !cocina.identification.respond_to?(:catalogLinks) || distinct_current_catalog_types.empty?

        distinct_current_catalog_types.map(&:capitalize)
      end

      def distinct_current_catalog_types
        # Filter out e.g. "previous symphony", "previous folio"
        @distinct_current_catalog_types ||=
          cocina.identification
                .catalogLinks
                .map(&:catalog)
                .uniq
                .sort
                .select { |catalog_type| catalog_type == CURRENT_CATALOG_TYPE }
      end

      # @param [Hash] solr_doc
      # @param [String] admin_policy_id
      def add_apo_titles(solr_doc, admin_policy_id)
        row = populate_cache(admin_policy_id)
        title = row['related_obj_title']
        if row['is_from_hydrus']
          solr_doc['hydrus_apo_title_ssim'] ||= []
          solr_doc['hydrus_apo_title_ssim'] << title
        else
          solr_doc['nonhydrus_apo_title_ssim'] ||= []
          solr_doc['nonhydrus_apo_title_ssim'] << title
        end
        solr_doc['apo_title_ssim'] ||= []
        solr_doc['apo_title_ssim'] << title
      end

      # populate cache if necessary
      def populate_cache(rel_druid)
        @@apo_hash[rel_druid] ||= begin
          related_obj = CocinaObjectStore.find(rel_druid)
          # APOs don't have projects, and since Hydrus is set to be retired, I don't want to
          # add the cocina property. Just check the tags service instead.
          is_from_hydrus = hydrus_tag?(rel_druid)
          title = Cocina::Models::Builders::TitleBuilder.build(related_obj.description.title)
          { 'related_obj_title' => title, 'is_from_hydrus' => is_from_hydrus }
        rescue CocinaObjectStore::CocinaObjectStoreError
          Honeybadger.notify("Bad association found on #{cocina.externalIdentifier}. #{rel_druid} could not be found")
          # This may happen if the given APO or Collection does not exist (bad data)
          { 'related_obj_title' => rel_druid, 'is_from_hydrus' => false }
        end
      end

      def hydrus_tag?(id)
        AdministrativeTags.for(identifier: id).include?('Project : Hydrus')
      end
    end
  end
end