pools: allow searching pools by post id or post count.

All pools containing post #1:

    https://danbooru.donmai.us/pools?search[post_ids_include]=1

All pools containing either post #1 or #2:

    https://danbooru.donmai.us/pools?search[post_ids_include]=1,2
    https://danbooru.donmai.us/pools?search[post_ids_include]=1+2

Pools with 1-100 posts:

    https://danbooru.donmai.us/pools?search[post_id_count]=1..100

Pools with no posts (empty pools):

    https://danbooru.donmai.us/pools?search[post_id_count]=0
This commit is contained in:
evazion
2019-09-06 16:18:29 -05:00
parent 7d07b5f289
commit a9b7503aa7
3 changed files with 54 additions and 3 deletions

View File

@@ -35,6 +35,18 @@ class ApplicationRecord < ActiveRecord::Base
where.not("#{qualified_column_for(attr)} ~ ?", "(?e)" + value)
end
def where_array_includes(attr, values)
where("#{qualified_column_for(attr)} && ARRAY[?]", values)
end
def where_array_count(attr, value)
relation = all
qualified_column = "cardinality(#{qualified_column_for(attr)})"
parsed_range = Tag.parse_helper(value, :integer)
PostQueryBuilder.new(nil).add_range_relation(parsed_range, qualified_column, relation)
end
def search_boolean_attribute(attribute, params)
return all unless params[attribute]
@@ -81,7 +93,8 @@ class ApplicationRecord < ActiveRecord::Base
end
def search_attribute(name, params)
type = type_for_attribute(name).type || reflect_on_association(name)&.class_name
column = column_for_attribute(name)
type = column.type || reflect_on_association(name)&.class_name
case type
when "User"
@@ -93,7 +106,11 @@ class ApplicationRecord < ActiveRecord::Base
when :boolean
search_boolean_attribute(name, params)
when :integer, :datetime
numeric_attribute_matches(name, params[name])
if column.array?
search_array_attribute(name, type, params)
else
numeric_attribute_matches(name, params[name])
end
else
raise NotImplementedError, "unhandled attribute type"
end
@@ -149,6 +166,21 @@ class ApplicationRecord < ActiveRecord::Base
relation
end
def search_array_attribute(name, type, params)
relation = all
if params[:"#{name}_include"] && type == :integer
items = params[:"#{name}_include"].to_s.scan(/\d+/).map(&:to_i)
relation = relation.where_array_includes(name, items)
end
if params[:"#{name.to_s.singularize}_count"]
relation = relation.where_array_count(name, params[:"#{name.to_s.singularize}_count"])
end
relation
end
def apply_default_order(params)
if params[:order] == "custom"
parse_ids = Tag.parse_helper(params[:id])

View File

@@ -57,7 +57,7 @@ class Pool < ApplicationRecord
def search(params)
q = super
q = q.search_attributes(params, :creator, :is_active, :is_deleted, :name, :description)
q = q.search_attributes(params, :creator, :is_active, :is_deleted, :name, :description, :post_ids)
q = q.text_attribute_matches(:description, params[:description_matches])
if params[:name_matches].present?

View File

@@ -59,6 +59,25 @@ class PoolTest < ActiveSupport::TestCase
assert_equal(@pool.id, Pool.find_by_name("test pool").id)
assert_equal(@pool.id, Pool.search(name_matches: "test pool").first.id)
end
should "find pools by post id" do
@pool1 = create(:pool, name: "pool1")
@pool2 = create(:pool, name: "pool2")
@post1 = create(:post, tag_string: "pool:pool1")
@post2 = create(:post, tag_string: "pool:pool2")
assert_equal([@pool1.id], Pool.search(post_ids_include: @post1.id).pluck(:id))
assert_equal([@pool2.id, @pool1.id], Pool.search(post_ids_include: "#{@post1.id} #{@post2.id}").pluck(:id))
end
should "find pools by post id count" do
@pool1 = create(:pool, name: "pool1")
@pool2 = create(:pool, name: "pool2")
@post1 = create(:post, tag_string: "pool:pool1")
@post2 = create(:post, tag_string: "pool:pool1")
assert_equal([@pool1.id], Pool.search(post_id_count: 2).pluck(:id))
end
end
context "Creating a pool" do