refactor: create story finder instead of doing all that junk inline

This commit is contained in:
Neetpone 2024-04-13 18:21:33 -04:00
parent 95a65e9a6e
commit f45ce86842
2 changed files with 47 additions and 16 deletions

View file

@ -2,7 +2,7 @@
# This whole class is a giant mess but I coded it fast so give me a break.
class SearchController < ApplicationController
ALLOWED_SORT_DIRS = %i[asc desc]
ALLOWED_SORT_FIELDS = %i[title author date_published date_updated num_words rel]
ALLOWED_SORT_FIELDS = %i[title author date_published date_updated num_words rating rel]
before_action :load_tags
@ -28,13 +28,10 @@ class SearchController < ApplicationController
# This was mainly written this way to match the way FiMFetch's query interface looks, without using JS.
# I should do a Derpibooru-esque textual search system sometime.
@search = Story.fancy_search(
@search = StoryFinder.new(@search_params).find(
per_page: @per_page,
page: @page_num
) do |s|
s.add_query(match: { title: { query: @search_params[:q], operator: :and } }) if @search_params[:q].present?
s.add_query(match: { author: { query: @search_params[:author], operator: :and } }) if @search_params[:author].present?
# tags -> match any of the included tags, exclude any of the excluded tags
tag_musts, tag_must_nots = parse_tag_queries
boolses = {}
@ -48,17 +45,6 @@ class SearchController < ApplicationController
) if tag_must_nots.any?
s.add_query(bool: boolses) if boolses.any?
# ratings -> match stories with any of them
s.add_filter(bool: {
should: @search_params[:ratings].keys.map { |k| { term: { content_rating: k } } }
}) if @search_params[:ratings].present?
# completeness -> match stories with any of them
s.add_filter(bool: {
should: @search_params[:state].keys.map { |k| { term: { completion_status: k } } }
}) if @search_params[:state].present?
# sort direction
if using_random
s.add_sort _random: :desc

45
app/lib/story_finder.rb Normal file
View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
class StoryFinder
# key is the params scalar field, value is the ES document field to search on
QUERIES = {
q: :title,
author: :author
}.freeze
# key is the params array field, value is the query type and the ES document field to search on.
FILTERS = {
ratings: { type: :should, field: :content_rating },
state: { type: :should, field: :completion_status }
}.freeze
def initialize(params)
@params = params
end
def find(opts)
Story.fancy_search(opts) do |s|
build_queries(s)
build_filters(s)
yield s if block_given?
end
end
private
# @param s FancySearchable::FancySearchableOptions
def build_queries(s)
QUERIES.each do |param, field|
s.add_query match: { field => { query: @params[param], operator: :and } } if @params[param].present?
end
end
# @param s FancySearchable::FancySearchableOptions
def build_filters(s)
FILTERS.each do |param, opts|
s.add_filter(bool: {
opts[:type] => @params[param].keys.map { |k| { term: { opts[:field] => k } } }
}) if @params[param].present?
end
end
end