comparison app/models/query.rb @ 1517:dffacf8a6908 redmine-2.5

Update to Redmine SVN revision 13367 on 2.5-stable branch
author Chris Cannam
date Tue, 09 Sep 2014 09:29:00 +0100
parents e248c7af89ec
children
comparison
equal deleted inserted replaced
1516:b450a9d58aed 1517:dffacf8a6908
240 when :float 240 when :float
241 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+(\.\d*)?$/) } 241 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+(\.\d*)?$/) }
242 when :date, :date_past 242 when :date, :date_past
243 case operator_for(field) 243 case operator_for(field)
244 when "=", ">=", "<=", "><" 244 when "=", ">=", "<=", "><"
245 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) } 245 add_filter_error(field, :invalid) if values_for(field).detect {|v|
246 v.present? && (!v.match(/\A\d{4}-\d{2}-\d{2}(T\d{2}((:)?\d{2}){0,2}(Z|\d{2}:?\d{2})?)?\z/) || parse_date(v).nil?)
247 }
246 when ">t-", "<t-", "t-", ">t+", "<t+", "t+", "><t+", "><t-" 248 when ">t-", "<t-", "t-", ">t+", "<t+", "t+", "><t+", "><t-"
247 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) } 249 add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) }
248 end 250 end
249 end 251 end
250 end 252 end
585 def sql_for_custom_field(field, operator, value, custom_field_id) 587 def sql_for_custom_field(field, operator, value, custom_field_id)
586 db_table = CustomValue.table_name 588 db_table = CustomValue.table_name
587 db_field = 'value' 589 db_field = 'value'
588 filter = @available_filters[field] 590 filter = @available_filters[field]
589 return nil unless filter 591 return nil unless filter
590 if filter[:format] == 'user' 592 if filter[:field].format.target_class && filter[:field].format.target_class <= User
591 if value.delete('me') 593 if value.delete('me')
592 value.push User.current.id.to_s 594 value.push User.current.id.to_s
593 end 595 end
594 end 596 end
595 not_in = nil 597 not_in = nil
622 case operator 624 case operator
623 when "=" 625 when "="
624 if value.any? 626 if value.any?
625 case type_for(field) 627 case type_for(field)
626 when :date, :date_past 628 when :date, :date_past
627 sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil)) 629 sql = date_clause(db_table, db_field, parse_date(value.first), parse_date(value.first))
628 when :integer 630 when :integer
629 if is_custom_filter 631 if is_custom_filter
630 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) = #{value.first.to_i})" 632 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) = #{value.first.to_i})"
631 else 633 else
632 sql = "#{db_table}.#{db_field} = #{value.first.to_i}" 634 sql = "#{db_table}.#{db_field} = #{value.first.to_i}"
657 when "*" 659 when "*"
658 sql = "#{db_table}.#{db_field} IS NOT NULL" 660 sql = "#{db_table}.#{db_field} IS NOT NULL"
659 sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter 661 sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
660 when ">=" 662 when ">="
661 if [:date, :date_past].include?(type_for(field)) 663 if [:date, :date_past].include?(type_for(field))
662 sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil) 664 sql = date_clause(db_table, db_field, parse_date(value.first), nil)
663 else 665 else
664 if is_custom_filter 666 if is_custom_filter
665 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) >= #{value.first.to_f})" 667 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) >= #{value.first.to_f})"
666 else 668 else
667 sql = "#{db_table}.#{db_field} >= #{value.first.to_f}" 669 sql = "#{db_table}.#{db_field} >= #{value.first.to_f}"
668 end 670 end
669 end 671 end
670 when "<=" 672 when "<="
671 if [:date, :date_past].include?(type_for(field)) 673 if [:date, :date_past].include?(type_for(field))
672 sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil)) 674 sql = date_clause(db_table, db_field, nil, parse_date(value.first))
673 else 675 else
674 if is_custom_filter 676 if is_custom_filter
675 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) <= #{value.first.to_f})" 677 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) <= #{value.first.to_f})"
676 else 678 else
677 sql = "#{db_table}.#{db_field} <= #{value.first.to_f}" 679 sql = "#{db_table}.#{db_field} <= #{value.first.to_f}"
678 end 680 end
679 end 681 end
680 when "><" 682 when "><"
681 if [:date, :date_past].include?(type_for(field)) 683 if [:date, :date_past].include?(type_for(field))
682 sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil)) 684 sql = date_clause(db_table, db_field, parse_date(value[0]), parse_date(value[1]))
683 else 685 else
684 if is_custom_filter 686 if is_custom_filter
685 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f})" 687 sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f})"
686 else 688 else
687 sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}" 689 sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}"
762 return sql 764 return sql
763 end 765 end
764 766
765 # Adds a filter for the given custom field 767 # Adds a filter for the given custom field
766 def add_custom_field_filter(field, assoc=nil) 768 def add_custom_field_filter(field, assoc=nil)
767 case field.field_format 769 options = field.format.query_filter_options(field, self)
768 when "text" 770 if field.format.target_class && field.format.target_class <= User
769 options = { :type => :text } 771 if options[:values].is_a?(Array) && User.current.logged?
770 when "list" 772 options[:values].unshift ["<< #{l(:label_me)} >>", "me"]
771 options = { :type => :list_optional, :values => field.possible_values } 773 end
772 when "date" 774 end
773 options = { :type => :date } 775
774 when "bool"
775 options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] }
776 when "int"
777 options = { :type => :integer }
778 when "float"
779 options = { :type => :float }
780 when "user", "version"
781 return unless project
782 values = field.possible_values_options(project)
783 if User.current.logged? && field.field_format == 'user'
784 values.unshift ["<< #{l(:label_me)} >>", "me"]
785 end
786 options = { :type => :list_optional, :values => values }
787 else
788 options = { :type => :string }
789 end
790 filter_id = "cf_#{field.id}" 776 filter_id = "cf_#{field.id}"
791 filter_name = field.name 777 filter_name = field.name
792 if assoc.present? 778 if assoc.present?
793 filter_id = "#{assoc}.#{filter_id}" 779 filter_id = "#{assoc}.#{filter_id}"
794 filter_name = l("label_attribute_of_#{assoc}", :name => filter_name) 780 filter_name = l("label_attribute_of_#{assoc}", :name => filter_name)
795 end 781 end
796 add_available_filter filter_id, options.merge({ 782 add_available_filter filter_id, options.merge({
797 :name => filter_name, 783 :name => filter_name,
798 :format => field.field_format,
799 :field => field 784 :field => field
800 }) 785 })
801 end 786 end
802 787
803 # Adds filters for the given custom fields scope 788 # Adds filters for the given custom fields scope
824 809
825 # Returns a SQL clause for a date or datetime field. 810 # Returns a SQL clause for a date or datetime field.
826 def date_clause(table, field, from, to) 811 def date_clause(table, field, from, to)
827 s = [] 812 s = []
828 if from 813 if from
829 from_yesterday = from - 1 814 if from.is_a?(Date)
830 from_yesterday_time = Time.local(from_yesterday.year, from_yesterday.month, from_yesterday.day) 815 from = Time.local(from.year, from.month, from.day).yesterday.end_of_day
816 else
817 from = from - 1 # second
818 end
831 if self.class.default_timezone == :utc 819 if self.class.default_timezone == :utc
832 from_yesterday_time = from_yesterday_time.utc 820 from = from.utc
833 end 821 end
834 s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_time.end_of_day)]) 822 s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from)])
835 end 823 end
836 if to 824 if to
837 to_time = Time.local(to.year, to.month, to.day) 825 if to.is_a?(Date)
826 to = Time.local(to.year, to.month, to.day).end_of_day
827 end
838 if self.class.default_timezone == :utc 828 if self.class.default_timezone == :utc
839 to_time = to_time.utc 829 to = to.utc
840 end 830 end
841 s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_time.end_of_day)]) 831 s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to)])
842 end 832 end
843 s.join(' AND ') 833 s.join(' AND ')
844 end 834 end
845 835
846 # Returns a SQL clause for a date or datetime field using relative dates. 836 # Returns a SQL clause for a date or datetime field using relative dates.
847 def relative_date_clause(table, field, days_from, days_to) 837 def relative_date_clause(table, field, days_from, days_to)
848 date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) 838 date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil))
839 end
840
841 # Returns a Date or Time from the given filter value
842 def parse_date(arg)
843 if arg.to_s =~ /\A\d{4}-\d{2}-\d{2}T/
844 Time.parse(arg) rescue nil
845 else
846 Date.parse(arg) rescue nil
847 end
849 end 848 end
850 849
851 # Additional joins required for the given sort options 850 # Additional joins required for the given sort options
852 def joins_for_order_statement(order_options) 851 def joins_for_order_statement(order_options)
853 joins = [] 852 joins = []