module Search class Username MAX_RESULTS = 6 ATTRIBUTES = %i[ id name profile_image username ].freeze # @param term [String] searches on username and name # @param context [Article] or [PodcastEpisode] # - used to rank search results by prior comment activity # - connected to comment via polymorphic Commentable def self.search_documents(term, context: nil, limit: MAX_RESULTS) results = new(context: context).search(term).limit(limit) serialize results end def self.serialize(results) Search::NestedUserSerializer .new(results, is_collection: true) .serializable_hash[:data] .pluck(:attributes) end def initialize(context: nil) @scope = scope_with_context(context) if context @scope ||= scope_without_context end def search(term) scope.search_by_name_and_username(term) end private attr_reader :scope def scope_without_context ::User.select(*ATTRIBUTES) end def scope_with_context(context) # PodcastEpisodes are also commentable but have more complex authorship user_ids = [context.try(:user_id)] user_ids += context.co_author_ids if context&.co_author_ids.present? user_ids += ::Comment.where(commentable: context).pluck(:user_id) selects = ATTRIBUTES.map { |sym| "users.#{sym}".to_sym } selects << ::User.sanitize_sql(["users.id IN (?) as has_commented", user_ids]) ::User .group("users.id") .select(*selects) .order("has_commented DESC") end private_class_method :serialize end end