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]}, |