unepwcmc/SAPI

View on GitHub
lib/modules/material_doc_ids_retriever.rb

Summary

Maintainability
A
3 hrs
Test Coverage
module MaterialDocIdsRetriever

  def self.run(params)
    params['taxon_concepts_ids'] =
      if params['taxon_name'].present?
        exact_match = MTaxonConcept.where("LOWER(full_name) = ?", params['taxon_name'].downcase)
                                   .where(taxonomy_id: 1)
                                   .first

        # retrieve the same taxa as shown in the page
        check_params = params.symbolize_keys
        ids =
          if params['scientific_name'].present? ||  params['country_ids'].present? ||  params['cites_appendices'].present?
            check_params[:scientific_name] = params['taxon_name']
            Checklist::Checklist.new(check_params).query.pluck(:id)

          else
            MTaxonConcept.by_cites_eu_taxonomy
                             .without_non_accepted
                             .without_hidden
                             .by_name(
                                params['taxon_name'],
                                { :synonyms => true, :common_names => true, :subspecies => false }
                               )
                             .order('rank_id ASC, full_name')
                             .pluck(:id)
          end

        anc_ids = []
        anc_ids = ancestors_ids(exact_match.try(:id), params['taxon_name'], exact_match).uniq  if ids.include?(exact_match.try(:id))
        anc_ids | ids
      elsif params['taxon_concept_id'].present?
        # retrieve all the ancestors taxa given a taxon(included)
        anc_ids = ancestors_ids(params['taxon_concept_id'])
        #retrieve all the children taxa given a taxon(included)
        chi_ids = MTaxonConcept.descendants_ids(params['taxon_concept_id']).map(&:to_i)
        anc_ids | chi_ids
      else
        check_params =
          if params.respond_to?(:permit!)
            params.dup.permit!.to_h.symbolize_keys
          else
            params.symbolize_keys
          end
        Checklist::Checklist.new(check_params).results.map(&:id)
      end

    return [] if params['taxon_concepts_ids'].empty?

    docs = DocumentSearch.new(
      params.merge(show_private: false, per_page: 10_000), 'public'
    )

    ordered_docs = docs.cached_results.sort_by do |doc|
      doc_tc_ids = doc.taxon_concept_ids
      params['taxon_concepts_ids'].index{ |id| doc_tc_ids.include? id }
    end

    doc_ids = ordered_docs.map { |doc| locale_document(doc) }.flatten
    doc_ids = doc_ids.map{ |d| d['id'] }
  end

  private

  def self.locale_document(doc)
    document = doc.document_language_versions.select { |h| h['locale_document'] == 'true' }
    document = doc.document_language_versions.select { |h| h['locale_document'] == 'default' } if document.empty?
    document
  end

  def self.ancestors_ids(tc_ids, taxon_name = nil, exact_match = nil)
    # TODO: Raise an error if any of these are not integers instead of leaving
    # it to the db to do this. That logic maybe belongs elsewhere?
    # Consider using `SearchParamSanitiser.sanitise_integer_array` for this.
    tc_ids_array = Array(tc_ids.is_a?(String) ? tc_ids.split(',') : tc_ids)
    tc_ids_sql = tc_ids_array.map(&:to_i).filter{ |tc_id| tc_id > 0 }.join(', ')

    # Don't bother running a query if we didn't get any taxon concept ids
    return [] if tc_ids_sql.empty?

    res = ApplicationRecord.connection.execute(
      <<-SQL
      SELECT ancestor_taxon_concept_id
      FROM taxon_concepts_and_ancestors_mview
      WHERE taxon_concept_id IN (#{tc_ids_sql})
      AND ancestor_taxon_concept_id IS NOT NULL
      ORDER BY
        #{order_case(exact_match, taxon_name)}
      tree_distance DESC, ancestor_taxon_concept_id;
      SQL
    )

    res.map(&:values).flatten.map(&:to_i).uniq
  end

  def self.order_case(match, taxon_name)
    return '' if (taxon_name.present? && match.nil?)
    query = "CASE
              WHEN taxon_concept_id = ancestor_taxon_concept_id
            "
    query += " AND taxon_concept_id = #{match.id} " if match
    query += " THEN -1
              END, "
    query
  end
end