# frozen_string_literal: true require 'active_support' require 'squeel' require_relative './text_to_tsquery' require_relative './text_to_sql_query' module PgSearchable extend ActiveSupport::Concern included do def update_pg_search_cache # kept just for compatibility with pg_searchable # noop in this implementation end end class_methods do def pg_search( fields: [], fields_mappings: {}, cache: nil, language: 'english', scope: 'scope_search', skip_callback: false, wildcard: true, external_cache_data: nil, joins: [], default_field: "" ) @ts_search_fields = fields @ts_search_fields_mappings = fields_mappings @ts_cache_field = cache @ts_language = language @ts_scope_method = scope @ts_skip_cache_update = skip_callback @ts_wildcard = wildcard @ts_joins = joins @default_field = (default_field.to_sym || fields.first) ts_add_scope end def ts_add_scope class_eval do scope ts_scope_method, ->(value) { ts_search(value) } end end def ts_search(value) return if @ts_search_fields.blank? || value.blank? TextToSqlQuery.new(value, @ts_search_fields, @default_field, @ts_search_fields_mappings).where_clause( includes(@ts_joins).references(:all)) end def should_update_cache_field? !@ts_skip_cache_update && @ts_cache_field.present? end def ts_cache_field @ts_cache_field end def ts_scope_method @ts_scope_method end def ts_cache_method @ts_cache_method end def ts_fields_to_vector(extra_data = []) field_to_vector = ->(field) { "to_tsvector('#{@ts_language}', coalesce(#{field}::text, ''))" } data_to_vector = ->(data) { "to_tsvector('#{@ts_language}', '#{data}')" } (@ts_search_fields.map(&field_to_vector) + extra_data.map(&data_to_vector)).join(' || ') end end end