Feature #38423 ยป 38423.patch
| app/models/query.rb | ||
|---|---|---|
| 313 | 313 |
"!p" => :label_no_issues_in_project, |
| 314 | 314 |
"*o" => :label_any_open_issues, |
| 315 | 315 |
"!o" => :label_no_open_issues, |
| 316 |
"/" => :label_matches_regexp |
|
| 316 | 317 |
} |
| 317 | 318 | |
| 318 | 319 |
class_attribute :operators_by_filter_type |
| ... | ... | |
| 323 | 324 |
:list_subprojects => [ "*", "!*", "=", "!" ], |
| 324 | 325 |
:date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "nd", "t", "ld", "nw", "w", "lw", "l2w", "nm", "m", "lm", "y", ">t-", "<t-", "><t-", "t-", "!*", "*" ], |
| 325 | 326 |
:date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "!*", "*" ], |
| 326 |
:string => [ "~", "=", "!~", "!", "^", "$", "!*", "*" ], |
|
| 327 |
:text => [ "~", "!~", "^", "$", "!*", "*" ], |
|
| 327 |
:string => [ "~", "=", "/", "!~", "!", "^", "$", "!*", "*" ],
|
|
| 328 |
:text => [ "~", "/", "!~", "^", "$", "!*", "*" ],
|
|
| 328 | 329 |
:search => [ "~", "!~" ], |
| 329 | 330 |
:integer => [ "=", ">=", "<=", "><", "!*", "*" ], |
| 330 | 331 |
:float => [ "=", ">=", "<=", "><", "!*", "*" ], |
| 331 | 332 |
:relation => ["=", "!", "=p", "=!p", "!p", "*o", "!o", "!*", "*"], |
| 332 | 333 |
:tree => ["=", "~", "!*", "*"] |
| 333 | 334 |
} |
| 335 |
unless Redmine::Database.supports_regexp? |
|
| 336 |
operators_by_filter_type[:string].delete('/')
|
|
| 337 |
operators_by_filter_type[:text].delete('/')
|
|
| 338 |
end |
|
| 334 | 339 | |
| 335 | 340 |
class_attribute :available_columns |
| 336 | 341 |
self.available_columns = [] |
| ... | ... | |
| 1435 | 1440 |
sql = sql_contains("#{db_table}.#{db_field}", value.first, :starts_with => true)
|
| 1436 | 1441 |
when "$" |
| 1437 | 1442 |
sql = sql_contains("#{db_table}.#{db_field}", value.first, :ends_with => true)
|
| 1443 |
when "/" |
|
| 1444 |
operator = Redmine::Database.regexp_operator |
|
| 1445 |
unless operator.nil? |
|
| 1446 |
sql = queried_class.send(:sanitize_sql_for_conditions, ["#{db_table}.#{db_field} #{operator} ?", value])
|
|
| 1447 |
end |
|
| 1438 | 1448 |
else |
| 1439 | 1449 |
raise QueryError, "Unknown query operator #{operator}"
|
| 1440 | 1450 |
end |
| config/locales/en.yml | ||
|---|---|---|
| 813 | 813 |
label_not_contains: doesn't contain |
| 814 | 814 |
label_starts_with: starts with |
| 815 | 815 |
label_ends_with: ends with |
| 816 |
label_matches_regexp: matches regexp |
|
| 816 | 817 |
label_any_issues_in_project: any issues in project |
| 817 | 818 |
label_any_issues_not_in_project: any issues not in project |
| 818 | 819 |
label_no_issues_in_project: no issues in project |
| lib/redmine/database.rb | ||
|---|---|---|
| 61 | 61 |
/mysql/i.match?(ActiveRecord::Base.connection.adapter_name) |
| 62 | 62 |
end |
| 63 | 63 | |
| 64 |
# Returns the MysQL version or nil if another DBMS is used |
|
| 65 |
def mysql_version |
|
| 66 |
mysql? ? ActiveRecord::Base.connection.select_value('SELECT VERSION()').to_s : nil
|
|
| 67 |
end |
|
| 68 | ||
| 64 | 69 |
# Returns a SQL statement for case/accent (if possible) insensitive match |
| 65 | 70 |
def like(left, right, options={})
|
| 66 | 71 |
neg = (options[:match] == false ? 'NOT ' : '') |
| ... | ... | |
| 103 | 108 |
def reset |
| 104 | 109 |
@postgresql_unaccent = nil |
| 105 | 110 |
end |
| 111 | ||
| 112 |
# Returns true if the database supports regular expressions |
|
| 113 |
def supports_regexp? |
|
| 114 |
regexp_operator.present? |
|
| 115 |
end |
|
| 116 | ||
| 117 |
# Returns the regexp operator for the current database |
|
| 118 |
# MySQL 8.0.4+ and PostgreSQL are supported |
|
| 119 |
def regexp_operator |
|
| 120 |
@regexp_operator ||= |
|
| 121 |
if mysql? && Gem::Version.new(mysql_version) >= Gem::Version.new('8.0.4')
|
|
| 122 |
'REGEXP' |
|
| 123 |
elsif postgresql? |
|
| 124 |
'~*' |
|
| 125 |
else |
|
| 126 |
nil |
|
| 127 |
end |
|
| 128 |
end |
|
| 106 | 129 |
end |
| 107 | 130 |
end |
| 108 | 131 |
end |
| test/unit/query_test.rb | ||
|---|---|---|
| 710 | 710 |
assert_not_include issue, result |
| 711 | 711 |
end |
| 712 | 712 | |
| 713 |
def test_operator_regexp |
|
| 714 |
skip unless Redmine::Database.supports_regexp? |
|
| 715 | ||
| 716 |
regexp_str = '(Recipes{0,1}|ingred.ents)'
|
|
| 717 |
query = IssueQuery.new(:name => '_') |
|
| 718 |
query.add_filter('subject', '/', [regexp_str])
|
|
| 719 |
result = find_issues_with_query(query) |
|
| 720 |
assert_equal [1, 2, 3], result.map(&:id).sort |
|
| 721 |
result.each {|issue| assert issue.subject =~ /#{regexp_str}/i}
|
|
| 722 |
end |
|
| 723 | ||
| 713 | 724 |
def test_range_for_this_week_with_week_starting_on_monday |
| 714 | 725 |
I18n.locale = :fr |
| 715 | 726 |
assert_equal '1', I18n.t(:general_first_day_of_week) |