Feature #4939 » issue4939_match_operators.patch
| config/locales/en.yml (date 1570461592896) | ||
|---|---|---|
| 1077 | 1077 |
label_orfilter_and_any: "AND any following" |
| 1078 | 1078 |
label_orfilter_or_any: "OR any following" |
| 1079 | 1079 |
label_orfilter_or_all: "OR all following" |
| 1080 |
label_match: "match" |
|
| 1081 |
label_not_match: "not match" |
|
| 1080 | 1082 | |
| 1081 | 1083 |
button_login: Login |
| 1082 | 1084 |
button_submit: Submit |
| app/models/query.rb (date 1570461296060) | ||
|---|---|---|
| 290 | 290 |
"!p" => :label_no_issues_in_project, |
| 291 | 291 |
"*o" => :label_any_open_issues, |
| 292 | 292 |
"!o" => :label_no_open_issues, |
| 293 |
"match" => :label_match, |
|
| 294 |
"!match" => :label_not_match |
|
| 293 | 295 |
} |
| 294 | 296 | |
| 295 | 297 |
class_attribute :operators_by_filter_type |
| ... | ... | |
| 301 | 303 |
:date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "nd", "t", "ld", "nw", "w", "lw", "l2w", "nm", "m", "lm", "y", ">t-", "<t-", "><t-", "t-", "!*", "*" ], |
| 302 | 304 |
:date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "!*", "*" ], |
| 303 | 305 |
:string => [ "~", "=", "!~", "!", "^", "$", "!*", "*" ], |
| 304 |
:text => [ "~", "!~", "^", "$", "!*", "*" ], |
|
| 306 |
:text => [ "~", "!~", "^", "$", "!*", "*", "match", "!match" ],
|
|
| 305 | 307 |
:integer => [ "=", ">=", "<=", "><", "!*", "*" ], |
| 306 | 308 |
:float => [ "=", ">=", "<=", "><", "!*", "*" ], |
| 307 | 309 |
:relation => ["=", "=p", "=!p", "!p", "*o", "!o", "!*", "*"], |
| ... | ... | |
| 1324 | 1326 |
sql = sql_contains("#{db_table}.#{db_field}", value.first, :starts_with => true)
|
| 1325 | 1327 |
when "$" |
| 1326 | 1328 |
sql = sql_contains("#{db_table}.#{db_field}", value.first, :ends_with => true)
|
| 1329 |
when "match" |
|
| 1330 |
sql = sql_for_match_operators(field, operator, value, db_table, db_field, is_custom_filter) |
|
| 1331 |
when "!match" |
|
| 1332 |
sql = sql_for_match_operators(field, operator, value, db_table, db_field, is_custom_filter) |
|
| 1327 | 1333 |
else |
| 1328 | 1334 |
raise "Unknown query operator #{operator}"
|
| 1329 | 1335 |
end |
| 1330 | 1336 | |
| 1337 |
return sql |
|
| 1338 |
end |
|
| 1339 | ||
| 1340 |
def sql_for_match_operators(field, operator, value, db_table, db_field, is_custom_filter=false) |
|
| 1341 |
sql = '' |
|
| 1342 |
v = "(" + value.first.strip + ")"
|
|
| 1343 | ||
| 1344 |
match = true |
|
| 1345 |
op = "" |
|
| 1346 |
term = "" |
|
| 1347 |
in_term = false |
|
| 1348 | ||
| 1349 |
in_bracket = false |
|
| 1350 | ||
| 1351 |
v.chars.each do |c| |
|
| 1352 | ||
| 1353 |
if (!in_bracket && "()+~!".include?(c) && in_term ) || (in_bracket && "}".include?(c)) |
|
| 1354 |
if !term.empty? |
|
| 1355 |
sql += "(" + sql_contains("#{db_table}.#{db_field}", term, match) + ")"
|
|
| 1356 |
end |
|
| 1357 |
#reset |
|
| 1358 |
op = "" |
|
| 1359 |
term = "" |
|
| 1360 |
in_term = false |
|
| 1361 | ||
| 1362 |
in_bracket = (c == "{")
|
|
| 1363 |
end |
|
| 1364 | ||
| 1365 |
if in_bracket && (!"{}".include? c)
|
|
| 1366 |
term += c |
|
| 1367 |
in_term = true |
|
| 1368 |
else |
|
| 1369 | ||
| 1370 |
case c |
|
| 1371 |
when "{"
|
|
| 1372 |
in_bracket = true |
|
| 1373 |
when "}" |
|
| 1374 |
in_bracket = false |
|
| 1375 |
when "("
|
|
| 1376 |
sql += c |
|
| 1377 |
when ")" |
|
| 1378 |
sql += c |
|
| 1379 |
when "+" |
|
| 1380 |
sql += " AND " if sql.last != "("
|
|
| 1381 |
when "~" |
|
| 1382 |
sql += " OR " if sql.last != "("
|
|
| 1383 |
when "!" |
|
| 1384 |
sql += " NOT " |
|
| 1385 |
else |
|
| 1386 |
if c != " " |
|
| 1387 |
term += c |
|
| 1388 |
in_term = true |
|
| 1389 |
end |
|
| 1390 |
end |
|
| 1391 | ||
| 1392 |
end |
|
| 1393 |
end |
|
| 1394 | ||
| 1395 |
if operator.include? "!" |
|
| 1396 |
sql = " NOT " + sql |
|
| 1397 |
end |
|
| 1398 | ||
| 1399 |
Rails.logger.info "MATCH EXPRESSION: V=#{value.first}, SQL=#{sql}"
|
|
| 1331 | 1400 |
return sql |
| 1332 | 1401 |
end |
| 1333 | 1402 | |
| test/unit/query_test.rb (date 1570461091027) | ||
|---|---|---|
| 1381 | 1381 |
assert_equal [5, 8, 9], issues.collect(&:id).sort |
| 1382 | 1382 |
end |
| 1383 | 1383 | |
| 1384 |
def test_filter_on_subject_match |
|
| 1385 |
query = IssueQuery.new(:name => '_') |
|
| 1386 |
query.filters = {'subject' => {:operator => 'match', :values => ['issue']}}
|
|
| 1387 |
issues = find_issues_with_query(query) |
|
| 1388 |
assert_equal [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], issues.collect(&:id).sort |
|
| 1389 | ||
| 1390 |
query = IssueQuery.new(:name => '_') |
|
| 1391 |
query.filters = {'subject' => {:operator => 'match', :values => ['(~project ~recipe) +!sub']}}
|
|
| 1392 |
issues = find_issues_with_query(query) |
|
| 1393 |
assert_equal [1, 3, 4, 14], issues.collect(&:id).sort |
|
| 1394 | ||
| 1395 |
query = IssueQuery.new(:name => '_') |
|
| 1396 |
query.filters = {'subject' => {:operator => 'match', :values => ['!(~sub project ~block) +issue']}}
|
|
| 1397 |
issues = find_issues_with_query(query) |
|
| 1398 |
assert_equal [4, 7, 8, 11, 12, 14], issues.collect(&:id).sort |
|
| 1399 | ||
| 1400 |
query = IssueQuery.new(:name => '_') |
|
| 1401 |
query.filters = {'subject' => {:operator => 'match', :values => ['+{closed ver} ~{locked ver}']}}
|
|
| 1402 |
issues = find_issues_with_query(query) |
|
| 1403 |
assert_equal [11, 12], issues.collect(&:id).sort |
|
| 1404 |
end |
|
| 1405 | ||
| 1406 |
def test_filter_on_subject_not_match |
|
| 1407 |
query = IssueQuery.new(:name => '_') |
|
| 1408 |
query.filters = {'subject' => {:operator => '!match', :values => ['issue']}}
|
|
| 1409 |
issues = find_issues_with_query(query) |
|
| 1410 |
assert_equal [1, 2, 3], issues.collect(&:id).sort |
|
| 1411 | ||
| 1412 |
query = IssueQuery.new(:name => '_') |
|
| 1413 |
query.filters = {'subject' => {:operator => '!match', :values => ['(~project ~recipe) +!sub']}}
|
|
| 1414 |
issues = find_issues_with_query(query) |
|
| 1415 |
assert_equal [2, 5, 6, 7, 8, 9, 10, 11, 12, 13], issues.collect(&:id).sort |
|
| 1416 | ||
| 1417 |
query = IssueQuery.new(:name => '_') |
|
| 1418 |
query.filters = {'subject' => {:operator => '!match', :values => ['!(~sub project ~block) +issue']}}
|
|
| 1419 |
issues = find_issues_with_query(query) |
|
| 1420 |
assert_equal [1, 2, 3, 5, 6, 9, 10, 13], issues.collect(&:id).sort |
|
| 1421 | ||
| 1422 |
query = IssueQuery.new(:name => '_') |
|
| 1423 |
query.filters = {'subject' => {:operator => '!match', :values => ['+{closed ver} ~{locked ver}']}}
|
|
| 1424 |
issues = find_issues_with_query(query) |
|
| 1425 |
assert_equal [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14], issues.collect(&:id).sort |
|
| 1426 |
end |
|
| 1427 | ||
| 1384 | 1428 |
def test_filter_on_orfilter_and_any |
| 1385 | 1429 |
query = IssueQuery.new(:name => '_') |
| 1386 | 1430 |
query.filters = {'project_id' => {:operator => '=', :values => [1]},
|