Module: PgFulltext::Query

Defined in:
lib/pg_fulltext/query.rb

Class Method Summary collapse

Class Method Details

.to_tsquery_string(query, prefix: true, operator: '&') ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/pg_fulltext/query.rb', line 3

def self.to_tsquery_string(query, prefix: true, operator: '&')

  # Parse out all [unicode] non-word and non-quote characters
  query.gsub!(/[^\s\p{L}"!]/, '')
  query.gsub!(/"+/, '"')
  query.gsub!(/\s+/, ' ')

  # Collect terms
  terms = []

  # Phrase mode
  if query.count('"') > 0 && query.count('"') % 2 == 0
    phrase_terms = []
    negate_phrase = false

    query_parts = query.split(' ')
    query_parts.each do |term|

      # Skip if completely comprised of non-unicode word characters
      next if term.gsub(/[^\s\p{L}]/, '') == ''

      if term.start_with?('!"') && !term.end_with?('"')
        phrase_terms << format_term(term[2..-1], prefix: true)
        negate_phrase = true
      elsif term.start_with?('"') && !term.end_with?('"')
        phrase_terms << format_term(term[1..-1], prefix: true)
      elsif phrase_terms.length > 0
        if term.end_with?('"')
          phrase_terms << format_term(term[0..-2], prefix: prefix)
          terms << "#{'!' if negate_phrase}(#{reject_falsy(phrase_terms, prefix: prefix).join(' <-> ')})"
          phrase_terms = []
          negate_phrase = false
        else
          phrase_terms << format_term(term, prefix: prefix)
        end
      else
        terms << format_term(term, prefix: prefix)
      end
    end
  else
    query.gsub! /["]/, ''
    terms = reject_falsy(query.split(' ').map { |v| format_term(v, prefix: prefix) }, prefix: prefix)
  end

  # Join terms with operator
  terms.join(" #{operator} ")
end