module QueryParser # Extracts the tokens from a query string # # === Parameters # * :query_string: the query to parse def parse(query_string) query_string.to_s.downcase.scan(/\S+/) end # Extracts the metatokens (tokens matching \S+:\S+). Returns a two element array: the first element contains plain tokens, and the second element contains metatokens. # # === Parameters # * :parsed_query: a list of tokens def parse_meta(parsed_query) hoge = [ [], {} ] parsed_query.each do |token| if token =~ /^(.+?):(.+)$/ hoge[1][Regexp.last_match[1]] = Regexp.last_match[2] else hoge[0] << token end end hoge end # Given an array of keywords to search for, return an array of strings for to_tsquery. # Words need to be escaped to prevent to_tsquery from parsing them as its own clumsy # search syntax; note that this is separate from SQL string escaping, and the final SQL # query will ultimately be double-escaped. def escape_for_tsquery(array) keywords = array.map do |token| next if token.empty? escaped_token = token.gsub(/\\|'/, '\0\0\0\0') "'" + escaped_token + "'" end.compact query = [] if keywords.any? query << "(" + keywords.join(" & ") + ")" end query end # Escape an SQL string. This is used only for escaping nested strings, within things like # to_tsquery parameters; the results must always be passed as a normal parameter to ensure # correct, safe escaping. def generate_sql_escape(token) escaped_token = token.gsub(/\\|'/, '\0\0\0\0').gsub("?", "\\\\77") "'" + escaped_token + "'" end module_function :parse module_function :parse_meta module_function :escape_for_tsquery module_function :generate_sql_escape end