-
Eugen Rochko authored19a64c96
# frozen_string_literal: true
class AccountSearchQueryBuilder
DISALLOWED_TSQUERY_CHARACTERS = /['?\\:‘’]/.freeze
LANGUAGE = Arel::Nodes.build_quoted('simple').freeze
EMPTY_STRING = Arel::Nodes.build_quoted('').freeze
WEIGHT_A = Arel::Nodes.build_quoted('A').freeze
WEIGHT_B = Arel::Nodes.build_quoted('B').freeze
WEIGHT_C = Arel::Nodes.build_quoted('C').freeze
FIELDS = {
display_name: { weight: WEIGHT_A }.freeze,
username: { weight: WEIGHT_B }.freeze,
domain: { weight: WEIGHT_C, nullable: true }.freeze,
}.freeze
RANK_NORMALIZATION = 32
DEFAULT_OPTIONS = {
limit: 10,
only_following: false,
}.freeze
# @param [String] terms
# @param [Hash] options
# @option [Account] :account
# @option [Boolean] :only_following
# @option [Integer] :limit
# @option [Integer] :offset
def initialize(terms, options = {})
@terms = terms
@options = DEFAULT_OPTIONS.merge(options)
end
# @return [ActiveRecord::Relation]
def build
search_scope.tap do |scope|
scope.merge!(personalization_scope) if with_account?
if with_account? && only_following?
scope.merge!(only_following_scope)
scope.with!(first_degree_definition) # `merge!` does not handle `with`
end
end
end
# @return [Array<Account>]
def results
build.to_a
end
private
def search_scope
Account.select(projections)
.where(match_condition)
.searchable
.includes(:account_stat)
.order(rank: :desc)
.limit(limit)
.offset(offset)
end
def personalization_scope
join_condition = accounts_table.join(follows_table, Arel::Nodes::OuterJoin)
.on(accounts_table.grouping(accounts_table[:id].eq(follows_table[:account_id]).and(follows_table[:target_account_id].eq(account.id))).or(accounts_table.grouping(accounts_table[:id].eq(follows_table[:target_account_id]).and(follows_table[:account_id].eq(account.id)))))
.join_sources
Account.joins(join_condition)