Module: Autoselect::Otu::ColExistingOtu

Defined in:
lib/autoselect/otu/col_existing_otu.rb

Overview

The existing Otu a Catalogue of Life result for a TaxonName yields, so selecting (or creating ancestors for) a CoL name that already has an Otu reuses it instead of making another. Shared by the OTU CoL levels, which put it in their results' hook, and the OTU CoL create endpoint.

An existing Otu is used when it's the TaxonName's only Otu, or its one Otu with no name of its own (named Otus alongside it are allowed - the modal warns about them). Otherwise (several named Otus, or several unnamed ones) which Otu is meant is the user's call: the result can't be selected or have ancestors created, and the user picks the Otu directly instead.

Defined Under Namespace

Classes: AmbiguousOtuError

Constant Summary collapse

CREATE_URL =
'/otus/autoselect_col_create'.freeze

Class Method Summary collapse

Class Method Details

.find_or_create_for(taxon_name_id, project_id:, user_id:) ⇒ Otu

Returns .selectable_otu, else a new Otu when the TaxonName has none.

Parameters:

  • taxon_name_id (Integer)
  • project_id (Integer)
  • user_id (Integer)

Returns:

  • (Otu) —

    .selectable_otu, else a new Otu when the TaxonName has none

Raises:



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/autoselect/otu/col_existing_otu.rb', line 94

def self.find_or_create_for(taxon_name_id, project_id:, user_id:)
  otus = otus_by_taxon_name([taxon_name_id], project_id:)[taxon_name_id] || []

  if otus.empty?
    return ::Otu.create!(taxon_name_id:, project_id:, by: user_id)
  end

  otu = selectable_otu(otus)
  return otu if otu

  raise AmbiguousOtuError,
    "#{otus.first.taxon_name.cached} has #{otus.size} OTUs - select " \
    'the OTU you want directly'
end

.hook(otus) ⇒ Hash

Returns the hook for an OTU CoL result. existing_id, existing_global_id and otu_label are .selectable_otu (nil when there's none), existing_named whether it has a name of its own; otu_count is every Otu on the TaxonName.

Parameters:

  • otus (Array<Otu>) —

    all of the TaxonName's Otus, empty when it has none

Returns:

  • (Hash) —

    the hook for an OTU CoL result. existing_id, existing_global_id and otu_label are .selectable_otu (nil when there's none), existing_named whether it has a name of its own; otu_count is every Otu on the TaxonName



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/autoselect/otu/col_existing_otu.rb', line 51

def self.hook(otus)
  existing_otu = selectable_otu(otus)
  {
    create_url: CREATE_URL,
    yields: 'otu_id',
    existing_id: existing_otu&.id,
    existing_global_id: existing_otu&.to_global_id&.to_s,
    existing_named: existing_otu ? existing_otu.name.present? : false,
    taxon_name_id: otus.first&.taxon_name_id,
    otu_count: otus.size,
    otu_label: existing_otu &&
      ApplicationController.helpers.label_for_otu(existing_otu)
  }
end

.otus_by_taxon_name(taxon_name_ids, project_id:) ⇒ Hash{Integer => Array<Otu>}

Returns every Otu per TaxonName id, for those that have any.

Parameters:

  • taxon_name_ids (Array<Integer, nil>)
  • project_id (Integer)

Returns:

  • (Hash{Integer => Array<Otu>}) —

    every Otu per TaxonName id, for those that have any



25
26
27
28
29
30
31
32
33
# File 'lib/autoselect/otu/col_existing_otu.rb', line 25

def self.otus_by_taxon_name(taxon_name_ids, project_id:)
  ids = taxon_name_ids.compact.uniq
  return {} if ids.empty?

  ::Otu.where(project_id:, taxon_name_id: ids)
    .includes(:taxon_name)
    .order(:id)
    .group_by(&:taxon_name_id)
end

.selectable_otu(otus) ⇒ Otu?

Returns the Otu a CoL result yields without the user choosing one: the only Otu, else the one Otu with no name of its own.

Parameters:

  • otus (Array<Otu>) —

    all of a TaxonName's Otus

Returns:

  • (Otu, nil) —

    the Otu a CoL result yields without the user choosing one: the only Otu, else the one Otu with no name of its own



38
39
40
41
42
43
# File 'lib/autoselect/otu/col_existing_otu.rb', line 38

def self.selectable_otu(otus)
  return otus.first if otus.size == 1

  unnamed = otus.select { |otu| otu.name.blank? }
  unnamed.size == 1 ? unnamed.first : nil
end

.wrap(records, project_id:) ⇒ Array<OpenStruct>

Returns the OTU CoL results for records, each one's hook carrying its TaxonName's Otus (see .hook).

Parameters:

  • records (Array<OpenStruct>) —

    TaxonName CoL level pseudo-records

  • project_id (Integer)

Returns:

  • (Array<OpenStruct>) —

    the OTU CoL results for records, each one's hook carrying its TaxonName's Otus (see .hook)



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/autoselect/otu/col_existing_otu.rb', line 70

def self.wrap(records, project_id:)
  otus_by_id = otus_by_taxon_name(
    records.map { |record| record._col_extension[:target_taxonworks_id] },
    project_id:
  )

  records.map do |record|
    otus = otus_by_id[record._col_extension[:target_taxonworks_id]] || []
    OpenStruct.new(
      id: nil,
      name: record.cached,
      taxon_name: nil,
      _col_extension: record._col_extension.merge(hook: hook(otus))
    )
  end
end