Feature #4939 » issue4939_orfilter.patch
| app/helpers/queries_helper.rb (working copy) | ||
|---|---|---|
| 41 | 41 | group = :label_date | 
| 42 | 42 | elsif %w(estimated_hours spent_time).include?(field) | 
| 43 | 43 | group = :label_time_tracking | 
| 44 | elsif field_options[:group] == 'or_filter' | |
| 45 | group = :label_orfilter | |
| 44 | 46 | end | 
| 45 | 47 | if group | 
| 46 | 48 | (grouped[group] ||= []) << [field_options[:name], field] | 
| app/models/issue_query.rb (working copy) | ||
|---|---|---|
| 202 | 202 | |
| 203 | 203 | add_available_filter "issue_id", :type => :integer, :label => :label_issue | 
| 204 | 204 | |
| 205 | add_available_filter "and_any", | |
| 206 | :name => l(:label_orfilter_and_any), | |
| 207 | :type => :list, | |
| 208 | :values => [l(:general_text_Yes)], | |
| 209 | :group => 'or_filter' | |
| 210 | add_available_filter "or_any", | |
| 211 | :name => l(:label_orfilter_or_any), | |
| 212 | :type => :list, | |
| 213 | :values => [l(:general_text_Yes)], | |
| 214 | :group => 'or_filter' | |
| 215 | add_available_filter "or_all", | |
| 216 | :name => l(:label_orfilter_or_all), | |
| 217 | :type => :list, | |
| 218 | :values => [l(:general_text_Yes)], | |
| 219 | :group => 'or_filter' | |
| 220 | ||
| 205 | 221 |     Tracker.disabled_core_fields(trackers).each {|field| | 
| 206 | 222 | delete_available_filter field | 
| 207 | 223 | } | 
| app/models/query.rb (working copy) | ||
|---|---|---|
| 883 | 883 | end | 
| 884 | 884 | |
| 885 | 885 | def statement | 
| 886 | # filters clauses | |
| 887 | filters_clauses = [] | |
| 886 | filters_clauses=[] | |
| 887 | and_clauses=[] | |
| 888 | and_any_clauses=[] | |
| 889 | or_any_clauses=[] | |
| 890 | or_all_clauses=[] | |
| 891 | and_any_op = "" | |
| 892 | or_any_op = "" | |
| 893 | or_all_op = "" | |
| 894 | ||
| 895 | #the AND filter start first | |
| 896 | filters_clauses = and_clauses | |
| 897 | ||
| 888 | 898 | filters.each_key do |field| | 
| 889 | 899 | next if field == "subproject_id" | 
| 900 | if field == "and_any" | |
| 901 | #start the and any part, point filters_clause to and_any_clauses | |
| 902 | filters_clauses = and_any_clauses | |
| 903 | and_any_op = operator_for(field) == "=" ? " AND " : " AND NOT " | |
| 904 | next | |
| 905 | elsif field == "or_any" | |
| 906 | #start the or any part, point filters_clause to or_any_clauses | |
| 907 | filters_clauses = or_any_clauses | |
| 908 | or_any_op = operator_for(field) == "=" ? " OR " : " OR NOT " | |
| 909 | next | |
| 910 | elsif field == "or_all" | |
| 911 | #start the or any part, point filters_clause to or_any_clauses | |
| 912 | filters_clauses = or_all_clauses | |
| 913 | or_all_op = operator_for(field) == "=" ? " OR " : " OR NOT " | |
| 914 | next | |
| 915 | end | |
| 916 | ||
| 890 | 917 | v = values_for(field).clone | 
| 891 | 918 | next unless v and !v.empty? | 
| 892 | 919 | operator = operator_for(field) | 
| ... | ... | |
| 916 | 943 | filters_clauses << sql_for_custom_field(field, operator, v, $1) | 
| 917 | 944 | elsif field =~ /^cf_(\d+)\.(.+)$/ | 
| 918 | 945 | filters_clauses << sql_for_custom_field_attribute(field, operator, v, $1, $2) | 
| 919 |       elsif respond_to?(method = "sql_for_#{field.tr('.','_')}_field") | |
| 946 |       elsif respond_to?(method = "sql_for_#{field.gsub('.','_')}_field") | |
| 920 | 947 | # specific statement | 
| 921 | 948 | filters_clauses << send(method, field, operator, v) | 
| 922 | 949 | else | 
| ... | ... | |
| 930 | 957 | filters_clauses << c.custom_field.visibility_by_project_condition | 
| 931 | 958 | end | 
| 932 | 959 | |
| 933 | filters_clauses << project_statement | |
| 934 | filters_clauses.reject!(&:blank?) | |
| 960 | #now start build the full statement, project filter is allways AND | |
| 961 | and_clauses.reject!(&:blank?) | |
| 962 |     and_statement = and_clauses.any? ? and_clauses.join(" AND ") : nil | |
| 935 | 963 | |
| 936 |     filters_clauses.any? ? filters_clauses.join(' AND ') : nil | |
| 964 |     all_and_statement = ["#{project_statement}", "#{and_statement}"].reject(&:blank?) | |
| 965 |     all_and_statement = all_and_statement.any? ? all_and_statement.join(" AND ") : nil | |
| 966 | ||
| 967 | ||
| 968 | # finish the traditional part. Now extended part | |
| 969 | # add the and_any first | |
| 970 | and_any_clauses.reject!(&:blank?) | |
| 971 |     and_any_statement = and_any_clauses.any? ? "("+ and_any_clauses.join(" OR ") +")" : nil | |
| 972 | ||
| 973 |     full_statement_ext_1 = ["#{all_and_statement}", "#{and_any_statement}"].reject(&:blank?) | |
| 974 | full_statement_ext_1 = full_statement_ext_1.any? ? full_statement_ext_1.join(and_any_op) : nil | |
| 975 | ||
| 976 | # then add the or_all | |
| 977 | or_all_clauses.reject!(&:blank?) | |
| 978 |     or_all_statement = or_all_clauses.any? ? "("+ or_all_clauses.join(" AND ") +")" : nil | |
| 979 | ||
| 980 |     full_statement_ext_2 = ["#{full_statement_ext_1}", "#{or_all_statement}"].reject(&:blank?) | |
| 981 | full_statement_ext_2 = full_statement_ext_2.any? ? full_statement_ext_2.join(or_all_op) : nil | |
| 982 | ||
| 983 | # then add the or_any | |
| 984 | or_any_clauses.reject!(&:blank?) | |
| 985 |     or_any_statement = or_any_clauses.any? ? "("+ or_any_clauses.join(" OR ") +")" : nil | |
| 986 | ||
| 987 |     full_statement = ["#{full_statement_ext_2}", "#{or_any_statement}"].reject(&:blank?) | |
| 988 | full_statement = full_statement.any? ? full_statement.join(or_any_op) : nil | |
| 989 | ||
| 990 |     Rails.logger.info "STATEMENT #{full_statement}" | |
| 991 | ||
| 992 | return full_statement | |
| 937 | 993 | end | 
| 938 | 994 | |
| 939 | 995 | # Returns the result count by group or nil if query is not grouped | 
| config/locales/de.yml (working copy) | ||
|---|---|---|
| 841 | 841 |     other: "%{count} Projekte" | 
| 842 | 842 | label_year: Jahr | 
| 843 | 843 | label_yesterday: gestern | 
| 844 | label_orfilter: "ODER Filter" | |
| 845 | label_orfilter_and_any: "UND einer der folgenden" | |
| 846 | label_orfilter_or_any: "ODER einer der folgenden" | |
| 847 | label_orfilter_or_all: "ODER alle folgenden" | |
| 844 | 848 | |
| 845 | 849 |   mail_body_account_activation_request: "Ein neuer Benutzer (%{value}) hat sich registriert. Sein Konto wartet auf Ihre Genehmigung:" | 
| 846 | 850 | mail_body_account_information: Ihre Konto-Informationen | 
| config/locales/en.yml (working copy) | ||
|---|---|---|
| 1072 | 1072 | label_password_char_class_lowercase: lowercase letters | 
| 1073 | 1073 | label_password_char_class_digits: digits | 
| 1074 | 1074 | label_password_char_class_special_chars: special characters | 
| 1075 | label_orfilter: "OR filters" | |
| 1076 | label_orfilter_and_any: "AND any following" | |
| 1077 | label_orfilter_or_any: "OR any following" | |
| 1078 | label_orfilter_or_all: "OR all following" | |
| 1075 | 1079 | |
| 1076 | 1080 | button_login: Login | 
| 1077 | 1081 | button_submit: Submit | 
| test/unit/query_test.rb (working copy) | ||
|---|---|---|
| 1381 | 1381 | assert_equal [5, 8, 9], issues.collect(&:id).sort | 
| 1382 | 1382 | end | 
| 1383 | 1383 | |
| 1384 | def test_filter_on_orfilter_and_any | |
| 1385 | query = IssueQuery.new(:name => '_') | |
| 1386 |     query.filters = {'project_id' => {:operator => '=', :values => [1]}, | |
| 1387 |                      'and_any' => {:operator => '=', :values => [1]}, | |
| 1388 |                      'status_id' => {:operator => '!', :values => [1]}, | |
| 1389 |                      'assigned_to_id' => {:operator => '=', :values => [3]}} | |
| 1390 | issues = find_issues_with_query(query) | |
| 1391 | assert_equal [2, 3, 8, 11, 12], issues.collect(&:id).sort | |
| 1392 | end | |
| 1393 | ||
| 1394 | def test_filter_on_orfilter_and_any_not | |
| 1395 | query = IssueQuery.new(:name => '_') | |
| 1396 |     query.filters = {'project_id' => {:operator => '=', :values => [1]}, | |
| 1397 |                      'and_any' => {:operator => '!', :values => [1]}, | |
| 1398 |                      'status_id' => {:operator => '=', :values => [2]}, | |
| 1399 |                      'author_id' => {:operator => '=', :values => [3]}} | |
| 1400 | issues = find_issues_with_query(query) | |
| 1401 | assert_equal [1, 3, 7, 8, 11], issues.collect(&:id).sort | |
| 1402 | end | |
| 1403 | ||
| 1404 | def test_filter_on_orfilter_or_any | |
| 1405 | query = IssueQuery.new(:name => '_') | |
| 1406 |     query.filters = {'status_id' => {:operator => '!', :values => [1]}, | |
| 1407 |                      'or_any' => {:operator => '=', :values => [1]}, | |
| 1408 |                      'project_id' => {:operator => '=', :values => [3]}, | |
| 1409 |                      'assigned_to_id' => {:operator => '=', :values => [2]}} | |
| 1410 | issues = find_issues_with_query(query) | |
| 1411 | assert_equal [2, 4, 5, 8, 11, 12, 13, 14], issues.collect(&:id).sort | |
| 1412 | end | |
| 1413 | ||
| 1414 | def test_filter_on_orfilter_or_any_not | |
| 1415 | query = IssueQuery.new(:name => '_') | |
| 1416 |     query.filters = {'status_id' => {:operator => '!', :values => [1]}, | |
| 1417 |                      'or_any' => {:operator => '!', :values => [1]}, | |
| 1418 |                      'project_id' => {:operator => '=', :values => [3]}, | |
| 1419 |                      'assigned_to_id' => {:operator => '!', :values => [2]}} | |
| 1420 | issues = find_issues_with_query(query) | |
| 1421 | assert_equal [2, 4, 8, 11, 12], issues.collect(&:id).sort | |
| 1422 | end | |
| 1423 | ||
| 1424 | def test_filter_on_orfilter_or_all | |
| 1425 | query = IssueQuery.new(:name => '_') | |
| 1426 |     query.filters = {'project_id' => {:operator => '=', :values => [3]}, | |
| 1427 |                      'or_all' => {:operator => '=', :values => [1]}, | |
| 1428 |                      'author_id' => {:operator => '=', :values => [2]}, | |
| 1429 |                      'assigned_to_id' => {:operator => '=', :values => [2]}} | |
| 1430 | issues = find_issues_with_query(query) | |
| 1431 | assert_equal [4, 5, 13, 14], issues.collect(&:id).sort | |
| 1432 | end | |
| 1433 | ||
| 1434 | def test_filter_on_orfilter_or_all_not | |
| 1435 | query = IssueQuery.new(:name => '_') | |
| 1436 |     query.filters = {'project_id' => {:operator => '=', :values => [3]}, | |
| 1437 |                      'or_all' => {:operator => '!', :values => [1]}, | |
| 1438 |                      'author_id' => {:operator => '=', :values => [2]}, | |
| 1439 |                      'assigned_to_id' => {:operator => '=', :values => [2]}} | |
| 1440 | issues = find_issues_with_query(query) | |
| 1441 | assert_equal [2, 3, 5, 12, 13, 14], issues.collect(&:id).sort | |
| 1442 | end | |
| 1443 | ||
| 1384 | 1444 | def test_statement_should_be_nil_with_no_filters | 
| 1385 | 1445 | q = IssueQuery.new(:name => '_') | 
| 1386 | 1446 |     q.filters = {} |