Class: FullSearch::Highlighter
- Inherits:
-
Object
- Object
- FullSearch::Highlighter
- Defined in:
- lib/full_search/highlighter.rb
Class Method Summary collapse
- .apply!(records, model, query) ⇒ Object
- .apply_fields!(records, model, query) ⇒ Object
- .build_field_snippets(model, query) ⇒ Object
- .build_snippets(model, query) ⇒ Object
- .connection ⇒ Object
- .exact_match_field_snippets(records, model, query) ⇒ Object
- .exact_match_field_value(em, record) ⇒ Object
- .highlight_rows(model, query) ⇒ Object
- .manual_field_snippets(records, model, query) ⇒ Object
- .manual_highlight(text, query, config) ⇒ Object
- .manual_snippets(records, model, query) ⇒ Object
- .quote(value) ⇒ Object
Class Method Details
.apply!(records, model, query) ⇒ Object
5 6 7 8 9 10 11 12 |
# File 'lib/full_search/highlighter.rb', line 5 def self.apply!(records, model, query) snippets = build_snippets(model, query) if snippets.values.all?(&:nil?) && records.any? snippets = manual_snippets(records, model, query) end records.each { |record| record.full_search_snippet = snippets[record.id] } records end |
.apply_fields!(records, model, query) ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/full_search/highlighter.rb', line 14 def self.apply_fields!(records, model, query) fields = build_field_snippets(model, query) if fields.empty? && records.any? fields = manual_field_snippets(records, model, query) end exact_fields = exact_match_field_snippets(records, model, query) records.each do |record| merged = fields[record.id] || {} exact_fields.fetch(record.id, {}).each { |k, v| merged[k] ||= v } record.full_search_highlight_fields = merged end records end |
.build_field_snippets(model, query) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/full_search/highlighter.rb', line 40 def self.build_field_snippets(model, query) rows = highlight_rows(model, query) dsl = model.full_search_dsl fields = dsl.fields open_tag = (dsl.highlight_config || { open_tag: "<mark>" })[:open_tag] rows.to_h do |row| snippets = fields.each_with_object({}) do |field, hash| snippet = row["#{field.name}_snippet"].to_s.strip key = field.as || field.name hash[key] = snippet if snippet.include?(open_tag) end [row["rowid"], snippets] end end |
.build_snippets(model, query) ⇒ Object
30 31 32 33 34 35 36 37 38 |
# File 'lib/full_search/highlighter.rb', line 30 def self.build_snippets(model, query) rows = highlight_rows(model, query) cols = model.full_search_dsl.fields.map(&:name) rows.to_h do |row| text = cols.map { |col| row["#{col}_snippet"] }.compact.join(" ").strip [row["rowid"], text.presence] end end |
.connection ⇒ Object
136 137 138 |
# File 'lib/full_search/highlighter.rb', line 136 def self.connection ActiveRecord::Base.connection end |
.exact_match_field_snippets(records, model, query) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/full_search/highlighter.rb', line 84 def self.exact_match_field_snippets(records, model, query) dsl = model.full_search_dsl return {} if dsl.exact_matches.empty? config = dsl.highlight_config || { open_tag: "<mark>", close_tag: "</mark>" } records.to_h do |record| snippets = dsl.exact_matches.each_with_object({}) do |em, hash| value = exact_match_field_value(em, record) highlighted = manual_highlight(value.to_s, query, config) hash[em.name.to_s] = highlighted if highlighted.include?(config[:open_tag]) end [record.id, snippets] end end |
.exact_match_field_value(em, record) ⇒ Object
100 101 102 103 104 105 106 |
# File 'lib/full_search/highlighter.rb', line 100 def self.exact_match_field_value(em, record) if em.source record.instance_exec(&em.source) else record.public_send(em.name) end end |
.highlight_rows(model, query) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/full_search/highlighter.rb', line 113 def self.highlight_rows(model, query) dsl = model.full_search_dsl config = dsl.highlight_config || { open_tag: "<mark>", close_tag: "</mark>" } match_expr = QueryParser.to_match_expression(QueryParser.parse(query)) return [] if match_expr.empty? table = FullSearch::Index.fts_table_name(model) cols = dsl.fields.map(&:name) return [] if cols.empty? highlight_parts = cols.each_with_index.map do |col, idx| "highlight(#{table}, #{idx}, #{quote(config[:open_tag])}, #{quote(config[:close_tag])}) AS #{col}_snippet" end.join(", ") sql = <<~SQL SELECT rowid, #{highlight_parts} FROM #{table} WHERE #{table} MATCH #{quote(match_expr)} SQL connection.execute(sql) end |
.manual_field_snippets(records, model, query) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/full_search/highlighter.rb', line 68 def self.manual_field_snippets(records, model, query) dsl = model.full_search_dsl config = dsl.highlight_config || { open_tag: "<mark>", close_tag: "</mark>" } fields = dsl.fields records.to_h do |record| snippets = fields.each_with_object({}) do |field, hash| value = record.full_search_text_for(field.name).to_s highlighted = manual_highlight(value, query, config) key = field.as || field.name hash[key] = highlighted if highlighted.include?(config[:open_tag]) end [record.id, snippets] end end |
.manual_highlight(text, query, config) ⇒ Object
108 109 110 111 |
# File 'lib/full_search/highlighter.rb', line 108 def self.manual_highlight(text, query, config) return text if text.empty? || query.empty? text.gsub(/#{Regexp.escape(query)}/i, "#{config[:open_tag]}\\0#{config[:close_tag]}") end |
.manual_snippets(records, model, query) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/full_search/highlighter.rb', line 56 def self.manual_snippets(records, model, query) dsl = model.full_search_dsl config = dsl.highlight_config || { open_tag: "<mark>", close_tag: "</mark>" } cols = dsl.fields.map(&:name) records.to_h do |record| text = cols.map { |col| record.full_search_text_for(col).to_s }.join(" ").strip highlighted = manual_highlight(text, query, config) [record.id, highlighted.presence] end end |
.quote(value) ⇒ Object
140 141 142 |
# File 'lib/full_search/highlighter.rb', line 140 def self.quote(value) connection.quote(value) end |