lib/pg_search/configuration.rb
# frozen_string_literal: true
require "pg_search/configuration/association"
require "pg_search/configuration/column"
require "pg_search/configuration/foreign_column"
module PgSearch
class Configuration
attr_reader :model
def initialize(options, model)
@options = default_options.merge(options)
@model = model
assert_valid_options(@options)
end
class << self
def alias(*strings)
name = Array(strings).compact.join("_")
# By default, PostgreSQL limits names to 32 characters, so we hash and limit to 32 characters.
"pg_search_#{Digest::SHA2.hexdigest(name)}".first(32)
end
end
def columns
regular_columns + associated_columns
end
def regular_columns
return [] unless options[:against]
Array(options[:against]).map do |column_name, weight|
Column.new(column_name, weight, model)
end
end
def associations
return [] unless options[:associated_against]
options[:associated_against].map do |association, column_names|
Association.new(model, association, column_names)
end.flatten
end
def associated_columns
associations.map(&:columns).flatten
end
def query
options[:query].to_s
end
def ignore
Array(options[:ignoring])
end
def ranking_sql
options[:ranked_by]
end
def features
Array(options[:using])
end
def feature_options
@feature_options ||= {}.tap do |hash|
features.map do |feature_name, feature_options|
hash[feature_name] = feature_options
end
end
end
def order_within_rank
options[:order_within_rank]
end
private
attr_reader :options
def default_options
{using: :tsearch}
end
VALID_KEYS = %w[
against ranked_by ignoring using query associated_against order_within_rank
].map(&:to_sym)
VALID_VALUES = {
ignoring: [:accents]
}.freeze
def assert_valid_options(options)
unless options[:against] || options[:associated_against] || using_tsvector_column?(options[:using])
raise(
ArgumentError,
"the search scope #{@name} must have :against, :associated_against, or :tsvector_column in its options"
)
end
options.assert_valid_keys(VALID_KEYS)
VALID_VALUES.each do |key, values_for_key|
Array(options[key]).each do |value|
raise ArgumentError, ":#{key} cannot accept #{value}" unless values_for_key.include?(value)
end
end
end
def using_tsvector_column?(options)
return unless options.is_a?(Hash)
options.dig(:dmetaphone, :tsvector_column).present? ||
options.dig(:tsearch, :tsvector_column).present?
end
end
end