summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorGo MAEDA <maeda@farend.jp>2023-04-14 23:50:26 +0000
committerGo MAEDA <maeda@farend.jp>2023-04-14 23:50:26 +0000
commit404a5b1de03011f65bf172a7f01a7cadbcf3ba9b (patch)
tree8603c81c807a7d9c3a588e08e491862b873c26fd /app
parentc54070cf18c8b0745ee6a08acb16310a702f6d5c (diff)
downloadredmine-404a5b1de03011f65bf172a7f01a7cadbcf3ba9b.tar.gz
redmine-404a5b1de03011f65bf172a7f01a7cadbcf3ba9b.zip
"contains any of" operator for text filters to perform OR search of multiple terms (#38435).
Patch by Go MAEDA. git-svn-id: https://svn.redmine.org/redmine/trunk@22188 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r--app/models/issue_query.rb8
-rw-r--r--app/models/query.rb18
2 files changed, 21 insertions, 5 deletions
diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb
index 68ce1c104..cd363b5c8 100644
--- a/app/models/issue_query.rb
+++ b/app/models/issue_query.rb
@@ -791,8 +791,14 @@ class IssueQuery < Query
projects = nil
end
+ is_all_words =
+ case operator
+ when '~' then true
+ when '|~', '!~' then false
+ end
+
fetcher = Redmine::Search::Fetcher.new(
- question, User.current, ['issue'], projects, all_words: (operator != '!~'), attachments: '0'
+ question, User.current, ['issue'], projects, all_words: is_all_words, attachments: '0'
)
ids = fetcher.result_ids.map(&:last)
if ids.present?
diff --git a/app/models/query.rb b/app/models/query.rb
index 289d683f6..10bd23adf 100644
--- a/app/models/query.rb
+++ b/app/models/query.rb
@@ -306,6 +306,7 @@ class Query < ActiveRecord::Base
"t-" => :label_ago,
"~" => :label_contains,
"!~" => :label_not_contains,
+ "|~" => :label_contains_any_of,
"^" => :label_starts_with,
"$" => :label_ends_with,
"=p" => :label_any_issues_in_project,
@@ -323,9 +324,9 @@ class Query < ActiveRecord::Base
:list_subprojects => [ "*", "!*", "=", "!" ],
:date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "nd", "t", "ld", "nw", "w", "lw", "l2w", "nm", "m", "lm", "y", ">t-", "<t-", "><t-", "t-", "!*", "*" ],
:date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "!*", "*" ],
- :string => [ "~", "=", "!~", "!", "^", "$", "!*", "*" ],
- :text => [ "~", "!~", "^", "$", "!*", "*" ],
- :search => [ "~", "!~" ],
+ :string => [ "~", "|~", "=", "!~", "!", "^", "$", "!*", "*" ],
+ :text => [ "~", "|~", "!~", "^", "$", "!*", "*" ],
+ :search => [ "~", "|~", "!~" ],
:integer => [ "=", ">=", "<=", "><", "!*", "*" ],
:float => [ "=", ">=", "<=", "><", "!*", "*" ],
:relation => ["=", "!", "=p", "=!p", "!p", "*o", "!o", "!*", "*"],
@@ -1431,6 +1432,8 @@ class Query < ActiveRecord::Base
sql = sql_contains("#{db_table}.#{db_field}", value.first)
when "!~"
sql = sql_contains("#{db_table}.#{db_field}", value.first, :match => false)
+ when "|~"
+ sql = sql_contains("#{db_table}.#{db_field}", value.first, :all_words => false)
when "^"
sql = sql_contains("#{db_table}.#{db_field}", value.first, :starts_with => true)
when "$"
@@ -1443,6 +1446,12 @@ class Query < ActiveRecord::Base
end
# Returns a SQL LIKE statement with wildcards
+ #
+ # valid options:
+ # * :match - use NOT LIKE if false
+ # * :starts_with - use LIKE 'value%' if true
+ # * :ends_with - use LIKE '%value' if true
+ # * :all_words - use OR instead of AND if false
def sql_contains(db_field, value, options={})
options = {} unless options.is_a?(Hash)
options.symbolize_keys!
@@ -1465,10 +1474,11 @@ class Query < ActiveRecord::Base
def self.tokenized_like_conditions(db_field, value, **options)
tokens = Redmine::Search::Tokenizer.new(value).tokens
tokens = [value] unless tokens.present?
+ logical_opr = options.delete(:all_words) == false ? ' OR ' : ' AND '
sql, values = tokens.map do |token|
[Redmine::Database.like(db_field, '?', options), "%#{sanitize_sql_like token}%"]
end.transpose
- [sql.join(" AND "), *values]
+ [sql.join(logical_opr), *values]
end
# rubocop:enable Lint/IneffectiveAccessModifier