From 3a28848ca03ae7d7e02c1bc9373a9f373cf0efeb Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 11 Jan 2009 16:33:51 +0000 Subject: [PATCH] Ability to sort the issue list by text, list, date and boolean custom fields (#1139). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2257 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/custom_field.rb | 21 +++++++++++++++++++++ app/models/custom_value.rb | 4 ++++ app/models/query.rb | 2 +- test/unit/query_test.rb | 26 ++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index 4759b714..344f277e 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -59,11 +59,32 @@ class CustomField < ActiveRecord::Base v.custom_field.is_required = false errors.add(:default_value, :activerecord_error_invalid) unless v.valid? end + + # Returns a ORDER BY clause that can used to sort customized + # objects by their value of the custom field. + # Returns false, if the custom field can not be used for sorting. + def order_statement + case field_format + when 'string', 'list', 'date', 'bool' + # COALESCE is here to make sure that blank and NULL values are sorted equally + "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + + " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + + " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + + " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" + else + nil + end + end def <=>(field) position <=> field.position end + def self.customized_class + self.name =~ /^(.+)CustomField$/ + begin; $1.constantize; rescue nil; end + end + # to move in project_custom_field def self.for_all find(:all, :conditions => ["is_for_all=?", true], :order => 'position') diff --git a/app/models/custom_value.rb b/app/models/custom_value.rb index 1d453baf..085d242f 100644 --- a/app/models/custom_value.rb +++ b/app/models/custom_value.rb @@ -30,6 +30,10 @@ class CustomValue < ActiveRecord::Base self.value == '1' end + def to_s + value.to_s + end + protected def validate if value.blank? diff --git a/app/models/query.rb b/app/models/query.rb index 1a484597..0016cb24 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -35,7 +35,7 @@ class QueryCustomFieldColumn < QueryColumn def initialize(custom_field) self.name = "cf_#{custom_field.id}".to_sym - self.sortable = false + self.sortable = custom_field.order_statement || false @cf = custom_field end diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index ac3e3cad..f4b25e51 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -175,6 +175,32 @@ class QueryTest < Test::Unit::TestCase assert q.has_column?(c) end + def test_sort_by_string_custom_field_asc + q = Query.new + c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' } + assert c + assert c.sortable + issues = Issue.find :all, + :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :conditions => q.statement, + :order => "#{c.sortable} ASC" + values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s} + assert_equal values.sort, values + end + + def test_sort_by_string_custom_field_desc + q = Query.new + c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' } + assert c + assert c.sortable + issues = Issue.find :all, + :include => [ :assigned_to, :status, :tracker, :project, :priority ], + :conditions => q.statement, + :order => "#{c.sortable} DESC" + values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s} + assert_equal values.sort.reverse, values + end + def test_label_for q = Query.new assert_equal 'assigned_to', q.label_for('assigned_to_id')