search: move misc search parsing helpers to PostQueryBuilder.

* Move various search parser helper methods (`has_metatag?`,
  `is_single_tag?` et al) from PostSets and the Tag model to
  PostQueryBuilder.

* Fix various minor bugs stemming from trying to check if a search query
  contains certain metatags using regexes or other adhoc techniques.
This commit is contained in:
evazion
2020-04-23 01:51:30 -05:00
parent 3dab648d0e
commit dd0d9dff4a
15 changed files with 114 additions and 147 deletions

View File

@@ -761,7 +761,7 @@ class PostQueryBuilder
terms << OpenStruct.new({ type: :metatag, name: metatag.downcase, value: value })
elsif scanner.scan(/[^ ]+/)
terms << OpenStruct.new({ type: :tag, value: scanner.matched.downcase })
terms << OpenStruct.new({ type: :tag, name: scanner.matched.downcase })
end
end
@@ -775,7 +775,7 @@ class PostQueryBuilder
elsif term.type == :metatag
"#{term.name}:#{term.value}"
elsif term.type == :tag
term.value
term.name
end
end
end
@@ -1097,7 +1097,7 @@ class PostQueryBuilder
end
else
parse_tag(term.value, q[:tags])
parse_tag(term.name, q[:tags])
end
end
@@ -1254,5 +1254,52 @@ class PostQueryBuilder
end
end
concerning :UtilityMethods do
def tags
scan_query.select { |term| term.type == :tag }
end
def metatags
scan_query.select { |term| term.type == :metatag }
end
def find_metatag(metatag)
metatags.find { |term| term.name == metatag.to_s.downcase }.try(:value)
end
def has_metatag?(*metatag_names)
metatags.any? { |term| term.name.in?(metatag_names.map(&:to_s).map(&:downcase)) }
end
def is_metatag?(name, value = nil)
if value.nil?
is_single_term? && has_metatag?(name)
else
is_single_term? && find_metatag(name) == value.to_s
end
end
def is_empty_search?
scan_query.size == 0
end
def is_single_term?
scan_query.size == 1
end
def is_single_tag?
is_single_term? && tags.size == 1
end
def is_simple_tag?
tag = tags.first&.name
is_single_tag? && !tag.starts_with?("-") && !tag.starts_with?("~") && !tag.include?("*")
end
def is_wildcard_search?
is_single_tag? && tags.first.name.include?("*")
end
end
memoize :scan_query, :split_query, :parse_query
end

View File

@@ -1,10 +1,11 @@
module PostSets
class Post
MAX_PER_PAGE = 200
attr_reader :tag_array, :page, :raw, :random, :post_count, :format
attr_reader :page, :raw, :random, :post_count, :format, :tag_string, :query
def initialize(tags, page = 1, per_page = nil, raw: false, random: false, format: "html")
@tag_array = PostQueryBuilder.new(tags).split_query
@query = PostQueryBuilder.new(tags)
@tag_string = tags
@page = page
@per_page = per_page
@raw = raw.to_s.truthy?
@@ -12,12 +13,8 @@ module PostSets
@format = format.to_s
end
def tag_string
@tag_string ||= tag_array.uniq.join(" ")
end
def humanized_tag_string
tag_array.map { |tag| tag.tr("_", " ").titleize }.to_sentence
query.split_query.map { |tag| tag.tr("_", " ").titleize }.to_sentence
end
def has_blank_wiki?
@@ -31,8 +28,8 @@ module PostSets
end
def tag
return nil if !is_single_tag?
@tag ||= Tag.find_by(name: Tag.normalize_name(tag_string))
return nil unless query.is_simple_tag?
@tag ||= Tag.find_by(name: query.tags.first.name)
end
def artist
@@ -42,15 +39,15 @@ module PostSets
end
def pool
name = Tag.has_metatag?(tag_array, :ordpool, :pool)
return nil unless is_single_tag? && name.present?
return nil unless query.is_metatag?(:pool) || query.is_metatag?(:ordpool)
name = query.find_metatag(:pool) || query.find_metatag(:ordpool)
@pool ||= Pool.find_by_name(name)
end
def favgroup
name = Tag.has_metatag?(tag_array, :favgroup)
return nil unless is_single_tag? && name.present?
return nil unless query.is_metatag?(:favgroup)
name = query.find_metatag(:favgroup)
@favgroup ||= FavoriteGroup.visible(CurrentUser.user).find_by_name_or_id(name, CurrentUser.user)
end
@@ -76,11 +73,11 @@ module PostSets
end
def per_page
(@per_page || Tag.has_metatag?(tag_array, :limit) || CurrentUser.user.per_page).to_i.clamp(0, MAX_PER_PAGE)
(@per_page || query.find_metatag(:limit) || CurrentUser.user.per_page).to_i.clamp(0, MAX_PER_PAGE)
end
def is_random?
random || Tag.has_metatag?(tag_array, :order) == "random"
random || query.find_metatag(:order) == "random"
end
def get_post_count
@@ -118,34 +115,14 @@ module PostSets
def hide_from_crawler?
return true if current_page > 1
return false if is_empty_tag? || is_simple_tag? || tag_string == "order:rank"
return false if query.is_empty_search? || query.is_simple_tag? || query.is_metatag?(:order, :rank)
true
end
def is_single_tag?
tag_array.size == 1
end
def is_simple_tag?
Tag.is_simple_tag?(tag_string)
end
def is_empty_tag?
tag_array.empty?
end
def is_pattern_search?
is_single_tag? && tag_string =~ /\*/ && tag_array.none? {|x| x =~ /^-?source:.+/}
end
def current_page
[page.to_i, 1].max
end
def is_saved_search?
tag_string =~ /search:/
end
def presenter
@presenter ||= ::PostSetPresenters::Post.new(self)
end

View File

@@ -56,7 +56,7 @@ class RelatedTagQuery
versions = PostVersion.where(updater_id: user.id).where("updated_at > ?", since).order(id: :desc).limit(max_edits)
tags = versions.flat_map(&:added_tags)
tags = tags.reject { |tag| Tag.is_metatag?(tag) }
tags = tags.select { |tag| PostQueryBuilder.new(tag).is_simple_tag? }
tags = tags.group_by(&:itself).transform_values(&:size).sort_by { |tag, count| [-count, tag] }.map(&:first)
tags.take(max_tags)
end