searchable: factor out metatag value parser.

Factor out the code that parses metatag values (e.g. `score:>5`) and
search URL params (e.g. `search[score]=>5`) into a RangeParser class.

Also fix a bug where, if the `search[order]=custom` param was used
without a `search[id]` param, an exception would be raised. Fix another
bug where if an invalid `search[id]` was provided, then the custom order
would be ignored and the search would be returned with the default order
instead. Now if you use `search[order]=custom` without a valid
`search[id]` param, the search will return no results.
This commit is contained in:
evazion
2022-09-26 22:46:46 -05:00
parent 65dbd89e25
commit 116c1f1af8
4 changed files with 201 additions and 148 deletions

View File

@@ -201,7 +201,7 @@ module Searchable
end
def attribute_matches(value, field, type = :integer)
operator, *args = PostQueryBuilder.parse_metatag_value(value, type)
operator, *args = RangeParser.parse(value, type)
relation = where_operator(field, operator, *args)
# XXX Hack to make negating the equality operator work correctly on nullable columns.
@@ -215,7 +215,7 @@ module Searchable
end
relation
rescue PostQueryBuilder::ParseError
rescue RangeParser::ParseError
none
end
@@ -223,15 +223,24 @@ module Searchable
SearchContext.new(all, params, current_user).search_attributes(attributes)
end
# Order according to the list of IDs in the given string.
#
# Post.order_custom("1,2,3") => [post #1, post #2, post #3]
def order_custom(string)
operator, ids = RangeParser.parse(string, :integer)
return none unless operator == :in
in_order_of(:id, ids)
rescue RangeParser::ParseError
none
end
def apply_default_order(params)
if params[:order] == "custom"
parse_ids = PostQueryBuilder.parse_range(params[:id], :integer)
if parse_ids[0] == :in
return in_order_of(:id, parse_ids[1])
end
order_custom(params[:id])
else
default_order
end
default_order
end
def default_order