Upstream sync
This commit was merged in pull request #1.
This commit is contained in:
@@ -42,14 +42,17 @@ module PgSearchable
|
||||
|
||||
def ts_add_scope
|
||||
class_eval do
|
||||
scope ts_scope_method, ->(value) { ts_search(value) }
|
||||
scope ts_scope_method, ->(value) do
|
||||
resulting_ids = ts_search(value).map(&:id)
|
||||
where(id: resulting_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ts_search(value)
|
||||
return if @ts_search_fields.blank? || value.blank?
|
||||
includes(@ts_joins).references(:all).where(
|
||||
TextToSqlQuery.new(value, @ts_search_fields, @default_field, @ts_search_fields_mappings).where_clause)
|
||||
TextToSqlQuery.new(value, @ts_search_fields, @default_field, @ts_search_fields_mappings).where_clause).distinct
|
||||
end
|
||||
|
||||
def should_update_cache_field?
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# transforms "english like" text queries into a where clause with regex
|
||||
# https://www.postgresql.org/docs/9.5/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
|
||||
|
||||
class TextToRegexQuery
|
||||
def initialize(text, fields, default_field, fields_mappings = {})
|
||||
@text = text.to_s.strip
|
||||
@fields = fields.map(&:to_sym)
|
||||
@default_field = default_field.to_sym
|
||||
@fields_mappings = fields_mappings.merge(@fields.reduce({}) do |mappings, field|
|
||||
table_name, field_name = field.to_s.split(".")
|
||||
mappings[field_name.to_sym] = field
|
||||
mappings
|
||||
end)
|
||||
end
|
||||
|
||||
def where_clause(query)
|
||||
@cleared_text = @text.dup
|
||||
@column_chunks = []
|
||||
remove_duplicated_spaces
|
||||
extract_columns
|
||||
escape_special_characters
|
||||
generate_where_clause(query)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def remove_duplicated_spaces
|
||||
@cleared_text.gsub!(/\s+/, ' ')
|
||||
end
|
||||
|
||||
def escape_special_characters
|
||||
@cleared_text.gsub!(/\_/, '\_')
|
||||
@cleared_text.tr!('\\', '\\')
|
||||
@cleared_text.gsub!(/%/, '\%')
|
||||
end
|
||||
|
||||
def extract_columns
|
||||
column_search_term_pairs = @cleared_text.scan(/([A-Za-z0-9_]+:[\w\_-]+)/)
|
||||
|
||||
@column_chunks = (column_search_term_pairs.flatten.map do |pair|
|
||||
column, term = pair.split(':')
|
||||
next unless @fields_mappings.include?(column.to_sym)
|
||||
@cleared_text.gsub!(pair, '')
|
||||
{ @fields_mappings[column.to_sym] => term }
|
||||
end).compact
|
||||
unless @cleared_text.strip.empty?
|
||||
@column_chunks = [{ @default_field.to_s => @cleared_text.strip }] + @column_chunks
|
||||
end
|
||||
@column_chunks
|
||||
end
|
||||
|
||||
def generate_where_clause(query)
|
||||
where_clause = ''
|
||||
columns = @column_chunks.map { |c| c.keys.first }
|
||||
values = @column_chunks.map { |c| c.values.first }
|
||||
|
||||
columns.each do |column|
|
||||
quoted_column = '"' + column.to_s.gsub(".",'"."') + '"'
|
||||
where_clause += "#{quoted_column} ILIKE ? OR "
|
||||
end
|
||||
where_clause += " 1<>1 "
|
||||
regexed_values = values.map { |v| "%#{v}%" }
|
||||
query.where([where_clause] + regexed_values)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user