Class: Pose::Search

Inherits:
Object
  • Object
show all
Defined in:
lib/pose/search.rb

Overview

A search operation.

Is given a query and search options, and returns the search results.

Instance Method Summary collapse

Constructor Details

#initialize(classes, query_string, options = {}) ⇒ Search

Returns a new instance of Search.

Parameters:

  • classes (Array<Class>)

    The classes to search over.

  • query_string (String)

    The full-text part of the search query.

  • options (defaults to: {})

    Additional search options:

    • where: additional where clauses

    • join: additional join clauses



13
14
15
# File 'lib/pose/search.rb', line 13

def initialize classes, query_string, options = {}
  @query = Query.new classes, query_string, options
end

Instance Method Details

#add_join(arel, join_expression) ⇒ Object

Adds the given join expression to the given arel query.



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/pose/search.rb', line 19

def add_join arel, join_expression
  case join_expression.class.name
    when 'Class'
      table_name = join_expression.name.tableize
      return arel.joins "INNER JOIN #{table_name} ON pose_assignments.posable_id=#{table_name}.id AND pose_assignments.posable_type='#{join_expression.name}'"
    when 'String', 'Symbol'
      return arel.joins join_expression
    else
      raise "Unknown join expression: #{join_expression}"
  end
end

#add_joins(arel) ⇒ Object

Creates a JOIN to the given expression.



33
34
35
36
37
# File 'lib/pose/search.rb', line 33

def add_joins arel
  @query.joins.inject(arel) do |memo, join_data|
    add_join memo, join_data
  end
end

#add_wheres(arel) ⇒ Object

Adds the WHERE clauses from the given query to the given arel construct.



41
42
43
# File 'lib/pose/search.rb', line 41

def add_wheres arel
  @query.where.inject(arel) { |memo, where| memo.where where }
end

#empty_resultObject

Returns an empty result structure.



47
48
49
50
51
52
53
# File 'lib/pose/search.rb', line 47

def empty_result
  {}.tap do |result|
    @query.class_names.each do |class_name|
      result[class_name] = []
    end
  end
end

#limit_ids(result) ⇒ Object

Truncates the result set based on the :limit parameter in the query.



57
58
59
60
61
62
# File 'lib/pose/search.rb', line 57

def limit_ids result
  return unless @query.has_limit?
  result.each do |clazz, ids|
    result[clazz] = ids.slice 0, @query.limit
  end
end

#load_classes(result) ⇒ Object

Converts the ids to classes, if the user wants classes.



66
67
68
69
70
71
72
73
# File 'lib/pose/search.rb', line 66

def load_classes result
  return if @query.ids_requested?
  result.each do |clazz, ids|
    if ids.size > 0
      result[clazz] = clazz.where(id: ids)
    end
  end
end

#merge_search_result_word_matches(result, class_name, ids) ⇒ Object

Merges the given posable object ids for a single query word into the given search result. Helper method for :search_words.



78
79
80
81
82
83
84
# File 'lib/pose/search.rb', line 78

def merge_search_result_word_matches result, class_name, ids
  if result.has_key? class_name
    result[class_name] = result[class_name] & ids
  else
    result[class_name] = ids
  end
end

#resultsObject

Returns the search results cached. Use this method to access the results of the search.



89
90
91
# File 'lib/pose/search.rb', line 89

def results
  @results ||= search
end

#searchObject

Performs a complete search. Clients should use :results to perform a search, since it caches the results.



97
98
99
100
101
102
103
104
105
# File 'lib/pose/search.rb', line 97

def search
  {}.tap do |result|
    search_words.each do |class_name, ids|
      result[class_name.constantize] = ids
    end
    limit_ids result
    load_classes result
  end
end

#search_word(word) ⇒ Object

Finds all matching ids for a single word of the search query.



109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/pose/search.rb', line 109

def search_word word
  empty_result.tap do |result|
    data = Assignment.joins(:word) \
                     .select('pose_assignments.posable_id, pose_assignments.posable_type') \
                     .where('pose_words.text LIKE ?', "#{word}%") \
                     .where('pose_assignments.posable_type IN (?)', @query.class_names)
    data = add_joins data
    data = add_wheres data
    Assignment.connection.select_all(data.to_sql).each do |pose_assignment|
      result[pose_assignment['posable_type']] << pose_assignment['posable_id'].to_i
    end
  end
end

#search_wordsObject

Returns all matching ids for all words of the search query.



125
126
127
128
129
130
131
132
133
# File 'lib/pose/search.rb', line 125

def search_words
  {}.tap do |result|
    @query.query_words.each do |query_word|
      search_word(query_word).each do |class_name, ids|
        merge_search_result_word_matches result, class_name, ids
      end
    end
  end
end