module PgFulltext::Query

Public Class Methods

to_tsquery_string(query, prefix: true, operator: '&') click to toggle source
# File lib/pg_fulltext/query.rb, line 17
def self.to_tsquery_string(query, prefix: true, operator: '&')
  query = normalize_query(query)

  terms = []
  Lexer.lex(query).each do |token|
    if token.type == :WORD
      terms << format_term(token.value, prefix: prefix)
    elsif %i[PHRASE NOT_PHRASE].include?(token.type)
      phrase_terms = Lexer.lex(token.value).map do |phrase_term|
        phrase_term.value.nil? ? nil : format_term(phrase_term.value, prefix: prefix)
      end.compact
      terms << "#{'!' if token.type == :NOT_PHRASE}(#{phrase_terms.join(' <-> ')})"
    end
  end

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

Private Class Methods

format_term(term, prefix: true) click to toggle source
# File lib/pg_fulltext/query.rb, line 45
def self.format_term(term, prefix: true)
  # Remove any ! that's not at the beginning of the term, as it will break the query
  term.gsub!(/(?<!^)!/, '')

  # Add the prefix if prefix is set
  "#{term}#{':*' if prefix}"
end
normalize_query(query) click to toggle source
# File lib/pg_fulltext/query.rb, line 37
def self.normalize_query(query)
  query
    .gsub(/[.,]/, ' ')            # Replace all periods and commas with spaces (reasonable delimiters)
    .gsub(/[^\s\p{L}0-9"!]/, '')  # Remove all non-unicode, whitespace, numbers, quotes ("), and bangs (!)
    .gsub(/\s+/, ' ')             # Replace repeat whitespace occurrences with single spaces
    .strip                        # Strip space from beginning and end of line
end
reject_falsy(terms) click to toggle source
# File lib/pg_fulltext/query.rb, line 53
def self.reject_falsy(terms)
  false_values = [nil, '', '"', '!', ':*', '":*', '!:*']
  terms.reject { |v| false_values.include?(v) }
end