Class: Queries::BiologicalAssociation::Autocomplete
Constant Summary
collapse
- DEFAULT_LIMIT =
50
Query::Autocomplete::DELEGATED_DEPTH, Query::Autocomplete::DELEGATED_MINIMUM_LENGTH, Query::Autocomplete::LITERAL_RESTRICTION_MAX
Instance Attribute Summary
#delegated_results, #dynamic_limit, #limit, #project_id, #query_string, #restrict_to
Attributes inherited from Query
#query_string, #terms
Instance Method Summary
collapse
-
#anatomical_part_autocomplete(side) ⇒ Queries::AnatomicalPart::Autocomplete
-
#anatomical_part_matches(anatomical_part_query, side, results_allowed) ⇒ Object
-
#autocomplete ⇒ Array
-
#base_query ⇒ Scope
Scoped to the project, so that queries that aren't joined to project-scoped records (e.g. #autocomplete_exact_id) are.
-
#biological_relationship_autocomplete ⇒ Queries::BiologicalRelationship::Autocomplete
-
#biological_relationship_matches(results_allowed) ⇒ Object
-
#collection_object_autocomplete(side) ⇒ Queries::CollectionObject::Autocomplete
-
#collection_object_matches(collection_object_query, side, results_allowed) ⇒ Object
-
#field_occurrence_autocomplete(side) ⇒ Queries::FieldOccurrence::Autocomplete
-
#field_occurrence_matches(field_occurrence_query, side, results_allowed) ⇒ Object
-
#initialize(string, project_id: nil, restrict_to: nil, limit: nil) ⇒ Autocomplete
constructor
A new instance of Autocomplete.
-
#joined_matches(related_table_name, related_type, side, ids, results_allowed) ⇒ Array<BiologicalAssociation>
Biological_associations where the subject or object (on side) is one of the related_klass records identified by ids, in ids order, at most results_allowed.
-
#ordered_lazy_queries ⇒ Array<Proc>
An ordered list of thunks, highest priority first.
-
#otu_autocomplete(side) ⇒ Queries::Otu::Autocomplete
-
#otu_matches(side, results_allowed) ⇒ Object
-
#side_autocomplete(autocomplete_klass, klass, side) ⇒ Query::Autocomplete
An autocomplete_klass autocomplete restricted to klass records on side (see #side_restriction), and limited to #limit, so that it returns enough candidates to fill the results.
-
#side_restriction(klass, side) ⇒ ActiveRecord::Relation
The klass records that are the side (:subject or :object) of a biological_association in the project (and in restrict_to, when given).
#apply_restriction, #asserted_object_autocomplete, #asserted_object_restriction, #autocomplete_cached, #autocomplete_cached_wildcard_anywhere, #autocomplete_common_name_exact, #autocomplete_common_name_like, #autocomplete_exact_id, #autocomplete_exactly_named, #autocomplete_named, #autocomplete_ordered_wildcard_pieces_in_cached, #cached_facet, #combine_or_clauses, #common_name_name, #common_name_table, #common_name_wild_pieces, #delegated_autocomplete, #exactly_named, #fragments, #integers, #least_levenshtein, #match_wildcard_end_in_cached, #match_wildcard_in_cached, #named, #only_ids, #only_integers?, #order_by_id_rank, #parent, #parent_child_join, #parent_child_where, #pieces, #safe_integers, #scope, #string_fragments, #wildcard_wrapped_integers, #wildcard_wrapped_years, #with_cached, #with_cached_like, #with_id, #with_project_id, #year_letter, #years
Methods inherited from Query
#alphabetic_strings, #alphanumeric_strings, base_name, #base_name, #build_terms, #cached_facet, #end_wildcard, #levenshtein_distance, #match_ordered_wildcard_pieces_in_cached, #no_terms?, referenced_klass, #referenced_klass, #referenced_klass_except, #referenced_klass_intersection, #referenced_klass_union, #start_and_end_wildcard, #start_wildcard, #table, #wildcard_pieces
Constructor Details
#initialize(string, project_id: nil, restrict_to: nil, limit: nil) ⇒ Autocomplete
Returns a new instance of Autocomplete.
7
8
9
|
# File 'lib/queries/biological_association/autocomplete.rb', line 7
def initialize(string, project_id: nil, restrict_to: nil, limit: nil)
super(string, project_id:, restrict_to:, limit:)
end
|
Instance Method Details
#anatomical_part_matches(anatomical_part_query, side, results_allowed) ⇒ Object
114
115
116
117
|
# File 'lib/queries/biological_association/autocomplete.rb', line 114
def anatomical_part_matches(anatomical_part_query, side, results_allowed)
ids = anatomical_part_query.limit(results_allowed).pluck(:id)
joined_matches('anatomical_parts', 'AnatomicalPart', side, ids, results_allowed)
end
|
#autocomplete ⇒ Array
169
170
171
172
173
174
175
176
177
178
179
180
|
# File 'lib/queries/biological_association/autocomplete.rb', line 169
def autocomplete
result = []
ordered_lazy_queries.each do |q|
remaining = limit - result.count
break if remaining <= 0
result += q.call(remaining)
result.uniq!
end
result.first(limit)
end
|
#base_query ⇒ Scope
Returns scoped to the project, so that queries that aren't joined to
project-scoped records (e.g. #autocomplete_exact_id) are.
14
15
16
17
18
|
# File 'lib/queries/biological_association/autocomplete.rb', line 14
def base_query
q = super
q = q.where(project_id:) if project_id.any?
q
end
|
65
66
67
68
|
# File 'lib/queries/biological_association/autocomplete.rb', line 65
def biological_relationship_autocomplete
@biological_relationship_autocomplete ||= Queries::BiologicalRelationship::Autocomplete
.new(query_string, project_id: project_id)
end
|
#biological_relationship_matches(results_allowed) ⇒ Object
119
120
121
122
123
124
125
126
127
128
129
130
131
|
# File 'lib/queries/biological_association/autocomplete.rb', line 119
def biological_relationship_matches(results_allowed)
ids = biological_relationship_autocomplete.all.limit(results_allowed).pluck(:id)
return [] if ids.empty?
q = order_by_id_rank(
base_query.where(biological_relationship_id: ids),
'biological_associations.biological_relationship_id', ids
).limit(results_allowed)
apply_restriction(q).to_a
end
|
#collection_object_matches(collection_object_query, side, results_allowed) ⇒ Object
104
105
106
107
|
# File 'lib/queries/biological_association/autocomplete.rb', line 104
def collection_object_matches(collection_object_query, side, results_allowed)
ids = collection_object_query.limit(results_allowed).pluck(:id)
joined_matches('collection_objects', 'CollectionObject', side, ids, results_allowed)
end
|
#field_occurrence_matches(field_occurrence_query, side, results_allowed) ⇒ Object
109
110
111
112
|
# File 'lib/queries/biological_association/autocomplete.rb', line 109
def field_occurrence_matches(field_occurrence_query, side, results_allowed)
ids = field_occurrence_query.limit(results_allowed).pluck(:id)
joined_matches('field_occurrences', 'FieldOccurrence', side, ids, results_allowed)
end
|
#joined_matches(related_table_name, related_type, side, ids, results_allowed) ⇒ Array<BiologicalAssociation>
Returns biological_associations where the subject or object (on side) is one of the
related_klass records identified by ids, in ids order, at most
results_allowed.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
# File 'lib/queries/biological_association/autocomplete.rb', line 79
def joined_matches(related_table_name, related_type, side, ids, results_allowed)
return [] if ids.empty?
foreign_key_column = "biological_association_#{side}_id"
type_column = "biological_association_#{side}_type"
q = base_query
.joins(
"JOIN #{related_table_name} ON biological_associations.#{foreign_key_column} = #{related_table_name}.id " \
"AND biological_associations.#{type_column} = '#{related_type}'"
)
.where(related_table_name.to_sym => { id: ids })
q = order_by_id_rank(q, "#{related_table_name}.id", ids).limit(results_allowed)
apply_restriction(q).to_a
end
|
#ordered_lazy_queries ⇒ Array<Proc>
Returns An ordered list of thunks, highest priority first. Each, when called with
the number of results still wanted, lazily runs its own query and returns an
Array. Kept as thunks (rather than eagerly building/running
every branch, as this used to) so autocomplete can stop pulling further branches,
and cap how many candidate ids a branch even asks for, once enough results are found.
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
# File 'lib/queries/biological_association/autocomplete.rb', line 139
def ordered_lazy_queries
queries = [->(n) {
q = autocomplete_exact_id
q ? apply_restriction(q).to_a : []
}]
queries << ->(n) { otu_matches(:subject, n) }
queries << ->(n) { otu_matches(:object, n) }
%i{subject object}.each do |side|
collection_object_autocomplete(side).base_queries
.each { |q| queries << ->(n) { collection_object_matches(q, side, n) } }
end
%i{subject object}.each do |side|
field_occurrence_autocomplete(side).base_queries
.each { |q| queries << ->(n) { field_occurrence_matches(q, side, n) } }
end
queries << ->(n) { biological_relationship_matches(n) }
%i{subject object}.each do |side|
anatomical_part_autocomplete(side).updated_queries
.each { |q| queries << ->(n) { anatomical_part_matches(q, side, n) } }
end
queries
end
|
50
51
52
|
# File 'lib/queries/biological_association/autocomplete.rb', line 50
def otu_autocomplete(side)
side_autocomplete(Queries::Otu::Autocomplete, ::Otu, side)
end
|
#otu_matches(side, results_allowed) ⇒ Object
99
100
101
102
|
# File 'lib/queries/biological_association/autocomplete.rb', line 99
def otu_matches(side, results_allowed)
ids = otu_autocomplete(side).distinct_autocomplete_base.limit(results_allowed).pluck(:id)
joined_matches('otus', 'Otu', side, ids, results_allowed)
end
|
#side_autocomplete(autocomplete_klass, klass, side) ⇒ Query::Autocomplete
Returns an autocomplete_klass autocomplete restricted to klass records on
side (see #side_restriction), and limited to #limit, so
that it returns enough candidates to fill the results. Both sides
share delegated results (e.g. the Otu autocompletes' TaxonName
fetch), see Query::Autocomplete#delegated_results.
42
43
44
45
46
47
|
# File 'lib/queries/biological_association/autocomplete.rb', line 42
def side_autocomplete(autocomplete_klass, klass, side)
@side_autocompletes ||= {}
@side_autocompletes[[autocomplete_klass, side]] ||= autocomplete_klass
.new(query_string, project_id:, restrict_to: side_restriction(klass, side), limit:)
.tap { |a| a.delegated_results = (@delegated_results ||= {}) }
end
|
#side_restriction(klass, side) ⇒ ActiveRecord::Relation
Returns the klass records that are the side (:subject or :object) of a
biological_association in the project (and in restrict_to, when
given). A candidate on a side is only useful if it is on that side
of some biological association; unrestricted, candidates that
aren't fill the subject/object autocompletes' limits and matching
biological associations are missed (e.g. a genus search matching
hundreds of species, few of which are in one).
28
29
30
31
32
33
34
|
# File 'lib/queries/biological_association/autocomplete.rb', line 28
def side_restriction(klass, side)
klass.where(
id: apply_restriction(base_query)
.where("biological_association_#{side}_type": klass.base_class.name)
.reselect("biological_association_#{side}_id")
)
end
|