Module: Specify::Model::TreeQueryable

Included in:
Geography, Taxonomy
Defined in:
lib/specify/models/tree_queryable.rb

Overview

TreeQueryable is a mixin that provides methods to query trees such as Specify::Model::Taxnoomy and Specify::Model::Geography.

Trees are nested hierarchies that are represented by three classes

  • an item class, holding information about the items to be classified in

a tree, such as taxonomic or geographic names.

  • a rank class, which designates items as belonging to a formal rank or

level within the tree

  • the tree class itself, which identifies all items and ranks belonging

to one tree.

For taxonomies, the tree class is Specify::Model::Taxonomy, the item class is Specify::Model::Taxon, the rank class is Specify::Model::Rank.

For geographies, the tree class is Specify::Model::Geography, the item class is Specify::Model::GeographicName, the rank class is Specify::Model::AdministrativeDivision.

Constant Summary collapse

AMBIGUOUS_MATCH_ERROR =
'Ambiguous results during tree search'

Instance Method Summary collapse

Instance Method Details

#rank(rank_name) ⇒ Object

Returns the rank instance in a tree for rank_name (a String).

rank classes are Specify::Model::AdministrativeDivision (for Specify::Model::Geography), and Specify::Model::Rank (for Specify::Model::Taxonomy).



31
32
33
# File 'lib/specify/models/tree_queryable.rb', line 31

def rank(rank_name)
  ranks_dataset.first(Name: rank_name.capitalize)
end

#search_tree(hash) ⇒ Object

Preforms a tree search, traversing a hierarchy from highest to lowest rank. hash is a Hash with the structure { 'rank' => 'name' } where rank is an existing rank name, name an existing item name with that rank. Give key value paris in descencing order of rank:

{ 'rank 1' => 'name',
  'rank 2' => 'name'
  'rank n' => 'name' }


43
44
45
46
47
48
49
50
51
52
# File 'lib/specify/models/tree_queryable.rb', line 43

def search_tree(hash)
  hash.reduce(nil) do |item, (rank_name, name)|
    searchset = item&.children_dataset || names_dataset
    item = searchset.where(Name: name,
                           rank: rank(rank_name))
    next item.first unless item.count > 1
    raise AMBIGUOUS_MATCH_ERROR +
          " for #{name}: #{item.to_a.map(&:FullName)}"
  end
end