Class: Huginn::Searchable::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/huginn/searchable/query.rb

Overview

Builds a tolerant full-text search relation over a model's searchable columns. The matching predicate per column is driven by Huginn.configuration.search_strategy (:pg_trgm, :full_text, :unaccent, :simple — or an Array of them combined with OR).

Columns are split in two groups following the datatable pattern:

* the model's own columns  -> direct fuzzy predicates on the base WHERE
* association columns      -> reverse semi-join subqueries anchored on
                             the first FK/has_many hop, so the base
                             table is never re-scanned:

   belongs_to ->  base[fk] IN (SELECT DISTINCT t1[pk]  FROM t1 ...)
   has_many   ->  base[pk]  IN (SELECT DISTINCT t1[fk] FROM t1 ...)

Through/hand-joined chains keep the generic fallback: base IN (SELECT DISTINCT base FROM base JOIN ...)

The base relation never carries joins, so every match group stays one query and the count remains a plain COUNT(*). Multiple association chains produce one subquery each, combined with OR.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, value, options = {}) ⇒ Query

Returns a new instance of Query.



34
35
36
37
38
39
# File 'lib/huginn/searchable/query.rb', line 34

def initialize(model, value, options = {})
  @model = model
  @value = value.to_s
  @options = options
  @distinct = options.fetch(:distinct, true)
end

Class Method Details

.call(model, value, options = {}) ⇒ Object



30
31
32
# File 'lib/huginn/searchable/query.rb', line 30

def self.call(model, value, options = {})
  new(model, value, options).call
end

Instance Method Details

#callObject



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/huginn/searchable/query.rb', line 41

def call
  relation = @model.all
  return apply_distinct(relation) if @value.strip.empty?

  resolution = resolve_columns
  predicates = fuzzy_predicates(resolution.fetch(:own))
  resolution.fetch(:associations).each do |_chain, group|
    predicate = association_predicate(group)
    predicates << predicate if predicate
  end

  return apply_distinct(relation) if predicates.empty?

  apply_distinct(relation.where(predicates.reduce(&:or)))
end