]> source.dussan.org Git - redmine.git/commitdiff
"starts with" and "ends with" filter operators for string values (#31879).
authorGo MAEDA <maeda@farend.jp>
Wed, 25 Sep 2019 16:24:08 +0000 (16:24 +0000)
committerGo MAEDA <maeda@farend.jp>
Wed, 25 Sep 2019 16:24:08 +0000 (16:24 +0000)
Patch by Yuichi HARADA.

git-svn-id: http://svn.redmine.org/redmine/trunk@18534 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/models/query.rb
config/locales/en.yml
test/unit/query_test.rb

index f5a0c2c6b5af0a0b9a027422f47f7b42def6b9cd..bd2b0c5c184688c79f1358f92a86538f19061f83 100644 (file)
@@ -282,6 +282,8 @@ class Query < ActiveRecord::Base
     "t-"  => :label_ago,
     "~"   => :label_contains,
     "!~"  => :label_not_contains,
+    "^"   => :label_starts_with,
+    "$"   => :label_ends_with,
     "=p"  => :label_any_issues_in_project,
     "=!p" => :label_any_issues_not_in_project,
     "!p"  => :label_no_issues_in_project,
@@ -297,8 +299,8 @@ class Query < ActiveRecord::Base
     :list_subprojects => [ "*", "!*", "=", "!" ],
     :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "nd", "t", "ld", "nw", "w", "lw", "l2w", "nm", "m", "lm", "y", ">t-", "<t-", "><t-", "t-", "!*", "*" ],
     :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "!*", "*" ],
-    :string => [ "~", "=", "!~", "!", "!*", "*" ],
-    :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
index d0c72ef694f5322c7120ed026d81c2b8e012b7e9..8fcc2262ae4a3557070b4a745ba5aaafca768e4d 100644 (file)
@@ -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
index 792ab60cf40f1493d8167eb4b11e241319153205..84bb1e93933f9466600a38c13d8eb05af87a4093 100644 (file)
@@ -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 = {}