diff --git a/app/models/query.rb b/app/models/query.rb index f5a0c2c6b..7f36e3016 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -287,6 +287,8 @@ class Query < ActiveRecord::Base "!p" => :label_no_issues_in_project, "*o" => :label_any_open_issues, "!o" => :label_no_open_issues, + "^=" => :label_starts_with, + "$=" => :label_ends_with, } class_attribute :operators_by_filter_type @@ -297,8 +299,8 @@ class Query < ActiveRecord::Base :list_subprojects => [ "*", "!*", "=", "!" ], :date => [ "=", ">=", "<=", "><", "t+", ">t-", " [ "=", ">=", "<=", "><", ">t-", " [ "~", "=", "!~", "!", "!*", "*" ], - :text => [ "~", "!~", "!*", "*" ], + :string => [ "~", "=", "!~", "!", "^=", "$=", "!*", "*" ], + :text => [ "~", "!~", "^=", "$=", "!*", "*" ], :integer => [ "=", ">=", "<=", "><", "!*", "*" ], :float => [ "=", ">=", "<=", "><", "!*", "*" ], :relation => ["=", "=p", "=!p", "!p", "*o", "!o", "!*", "*"], @@ -1260,7 +1262,11 @@ class Query < ActiveRecord::Base when "~" sql = sql_contains("#{db_table}.#{db_field}", value.first) when "!~" - sql = sql_contains("#{db_table}.#{db_field}", value.first, false) + sql = sql_contains("#{db_table}.#{db_field}", value.first, :match => false) + when "^=" + sql = sql_contains("#{db_table}.#{db_field}", value.first, :starts_with => true) + when "$=" + sql = sql_contains("#{db_table}.#{db_field}", value.first, :ends_with => true) else raise "Unknown query operator #{operator}" end @@ -1269,9 +1275,15 @@ class Query < ActiveRecord::Base end # Returns a SQL LIKE statement with wildcards - def sql_contains(db_field, value, match=true) + def sql_contains(db_field, value, options={}) + options = {} unless options.is_a?(Hash) + options.symbolize_keys! + prefix = suffix = nil + prefix = '%' if options[:ends_with] + suffix = '%' if options[:starts_with] + prefix = suffix = '%' if prefix.nil? && suffix.nil? queried_class.send :sanitize_sql_for_conditions, - [Redmine::Database.like(db_field, '?', :match => match), "%#{value}%"] + [Redmine::Database.like(db_field, '?', :match => options[:match]), "#{prefix}#{value}#{suffix}"] end # Adds a filter for the given custom field diff --git a/config/locales/en.yml b/config/locales/en.yml index d0c72ef69..8fcc2262a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -771,6 +771,8 @@ en: label_ago: days ago label_contains: contains label_not_contains: doesn't contain + label_starts_with: starts with + label_ends_with: ends with label_any_issues_in_project: any issues in project label_any_issues_not_in_project: any issues not in project label_no_issues_in_project: no issues in project diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index 792ab60cf..884e1b9b1 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -1353,6 +1353,20 @@ class QueryTest < ActiveSupport::TestCase assert_nil issues.detect {|issue| issue.attachments.any? {|attachment| attachment.filename.include?('error281')}} end + def test_filter_on_subject_when_starts_with + query = IssueQuery.new(:name => '_') + query.filters = {'subject' => {:operator => '^=', :values => ['issue']}} + issues = find_issues_with_query(query) + assert_equal [4, 6, 7, 10], issues.collect(&:id).sort + end + + def test_filter_on_subject_when_ends_with + query = IssueQuery.new(:name => '_') + query.filters = {'subject' => {:operator => '$=', :values => ['issue']}} + issues = find_issues_with_query(query) + assert_equal [5, 8, 9], issues.collect(&:id).sort + end + def test_statement_should_be_nil_with_no_filters q = IssueQuery.new(:name => '_') q.filters = {}