Mercurial > hg > soundsoftware-site
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 = [] |