diff --git a/app/models/post.rb b/app/models/post.rb index 512e2d1dc..61031bd2f 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1218,14 +1218,14 @@ class Post < ApplicationRecord end def get_count_from_cache(tags) - count = Cache.get(count_cache_key(tags)) # this will only have a value for multi-tag searches - - if count.nil? && !tags.include?(" ") + if Tag.is_simple_tag?(tags) count = select_value_sql("SELECT post_count FROM tags WHERE name = ?", tags.to_s) - # set_count_in_cache(tags, count.to_i) if count + else + # this will only have a value for multi-tag searches or single metatag searches + count = Cache.get(count_cache_key(tags)) end - count ? count.to_i : nil + count.try(:to_i) end def set_count_in_cache(tags, count, expiry = nil) diff --git a/app/models/tag.rb b/app/models/tag.rb index e4baa1896..94fcbb2f1 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -415,6 +415,12 @@ class Tag < ApplicationRecord end end + # true if query is a single "simple" tag (not a metatag, negated tag, or wildcard tag). + def is_simple_tag?(query) + q = parse_query(query) + (scan_query(query).size == 1) && (q[:tags][:related].size == 1) + end + def parse_query(query, options = {}) q = {} @@ -783,6 +789,10 @@ class Tag < ApplicationRecord end module SearchMethods + def empty + where("tags.post_count <= 0") + end + def nonempty where("tags.post_count > 0") end diff --git a/script/fixes/051_purge_invalid_tags.rb b/script/fixes/051_purge_invalid_tags.rb new file mode 100755 index 000000000..1c168ab7f --- /dev/null +++ b/script/fixes/051_purge_invalid_tags.rb @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment')) + +CurrentUser.user = User.system +CurrentUser.ip_addr = "127.0.0.1" + +Tag.transaction do + empty_gentags = Tag.empty.where(category: Tag.categories.general) + total = empty_gentags.count + + empty_gentags.find_each.with_index do |tag, i| + STDERR.puts %{validating "#{tag.name}" (#{i}/#{total})} if i % 1000 == 0 + + if tag.invalid?(:create) + # puts ({ name: tag.name, id: tag.id }).to_json + tag.delete + end + end +end diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb index f53d2f8b0..1092403e6 100644 --- a/test/unit/post_test.rb +++ b/test/unit/post_test.rb @@ -2388,13 +2388,39 @@ class PostTest < ActiveSupport::TestCase Danbooru.config.stubs(:blank_tag_search_fast_count).returns(nil) Danbooru.config.stubs(:estimate_post_counts).returns(false) FactoryGirl.create(:tag_alias, :antecedent_name => "alias", :consequent_name => "aaa") - FactoryGirl.create(:post, :tag_string => "aaa") + FactoryGirl.create(:post, :tag_string => "aaa", "score" => 42) + end + + context "a single basic tag" do + should "return the cached count" do + Tag.find_or_create_by_name("aaa").update_columns(post_count: 100) + assert_equal(100, Post.fast_count("aaa")) + end + end + + context "a single metatag" do + should "return the correct cached count" do + FactoryGirl.build(:tag, name: "score:42", post_count: -100).save(validate: false) + Post.set_count_in_cache("score:42", 100) + + assert_equal(100, Post.fast_count("score:42")) + end + end + + context "a multi-tag search" do + should "return the cached count, if it exists" do + Post.set_count_in_cache("aaa score:42", 100) + assert_equal(100, Post.fast_count("aaa score:42")) + end + + should "return the true count, if not cached" do + assert_equal(1, Post.fast_count("aaa score:42")) + end end context "a blank search" do should "should execute a search" do Cache.delete(Post.count_cache_key('')) - Post.expects(:select_value_sql).with(kind_of(String), "").once.returns(nil) Post.expects(:fast_count_search).with("", kind_of(Hash)).once.returns(1) assert_equal(1, Post.fast_count("")) end @@ -2428,7 +2454,6 @@ class PostTest < ActiveSupport::TestCase end should "execute a search" do - Post.expects(:select_value_sql).once.with(kind_of(String), "rating:s").returns(nil) Post.expects(:fast_count_search).once.with("rating:s", kind_of(Hash)).returns(1) assert_equal(1, Post.fast_count("")) end