diff --git a/app/controllers/cost_reports_controller.rb b/app/controllers/cost_reports_controller.rb index 833438b2fd..835df710f3 100644 --- a/app/controllers/cost_reports_controller.rb +++ b/app/controllers/cost_reports_controller.rb @@ -1,6 +1,7 @@ class CostReportsController < ApplicationController before_filter :find_optional_project, :only => [:index] before_filter :generate_query, :only => [:index] + before_filter :load_all helper :reporting include ReportingHelper @@ -117,6 +118,11 @@ class CostReportsController < ApplicationController end end + def load_all + CostQuery::GroupBy.all + CostQuery::Filter.all + end + private ## FIXME: Remove this once we moved to Redmine 1.0 def find_optional_project diff --git a/app/models/cost_query/chainable.rb b/app/models/cost_query/chainable.rb index 6c8d786150..550a8b0b03 100644 --- a/app/models/cost_query/chainable.rb +++ b/app/models/cost_query/chainable.rb @@ -6,8 +6,8 @@ class CostQuery < ActiveRecord::Base include CostQuery::QueryUtils extend CostQuery::InheritedAttribute - inherited_attribute :applies_for, - :default => :label_cost_entry_attributes #this attr. should point to a symbol useable for translations + # this attr. should point to a symbol useable for translations + inherited_attribute :applies_for, :default => :label_cost_entry_attributes def self.accepts_property(*list) CostQuery.accepted_properties.push(*list.map(&:to_s)) diff --git a/app/models/cost_query/custom_field_mixin.rb b/app/models/cost_query/custom_field_mixin.rb new file mode 100644 index 0000000000..d84955daa3 --- /dev/null +++ b/app/models/cost_query/custom_field_mixin.rb @@ -0,0 +1,57 @@ +module CostQuery::CustomFieldMixin + def self.extended(base) + base.inherited_attribute :factory + base.factory = base + super + end + + def all + @all ||= generate_subclasses + end + + def generate_subclasses + IssueCustomField.all.map do |field| + class_name = class_name_for field.name + parent.send(:remove_const, class_name) if CostQuery::GroupBy.const_defined? class_name + parent.const_set class_name, Class.new(self).prepare(field, class_name) + end + end + + def on_prepare(&block) + @on_prepare = block if block + @on_prepare + end + + def prepare(field, class_name) + label field.name + table_name(class_name.demodulize.underscore.tableize) + dont_inherit :group_fields + join_table (<<-SQL % [CustomValue.table_name, table_name, field.id, field.name]).gsub(/^ /, "\t") + -- BEGIN Custom Field Join: "%4$s" + LEFT OUTER JOIN ( + \tSELECT + \t\tvalue AS %2$s, + \t\tcustomized_type, + \t\tcustom_field_id, + \t\tcustomized_id + \tFROM + \t\t%1$s) + AS %2$s + ON %2$s.customized_type = 'Issue' + AND %2$s.custom_field_id = %3$d + AND %2$s.customized_id = entries.issue_id + -- END Custom Field Join: "%4$s" + SQL + instance_eval(&factory.on_prepare) + self + end + + def new(*) + fail "Only subclasses of #{self} should be instanciated." unless self < factory + super + end + + def class_name_for(field) + "CustomField" << field.split(/[ \-_]/).map { |part| part.gsub(/\W/, '').capitalize }.join + end +end \ No newline at end of file diff --git a/app/models/cost_query/group_by.rb b/app/models/cost_query/group_by.rb index 785d619d00..da723a4df5 100644 --- a/app/models/cost_query/group_by.rb +++ b/app/models/cost_query/group_by.rb @@ -21,9 +21,6 @@ module CostQuery::GroupBy ] end - # trigger eager loading - all - def self.all_grouped all.group_by { |g| g.applies_for }.to_a.sort { |a,b| a.first.to_s <=> b.first.to_s } end diff --git a/app/models/cost_query/group_by/custom_field.rb b/app/models/cost_query/group_by/custom_field.rb index c511120c89..620a2ad224 100644 --- a/app/models/cost_query/group_by/custom_field.rb +++ b/app/models/cost_query/group_by/custom_field.rb @@ -1,48 +1,6 @@ module CostQuery::GroupBy class CustomField < Base - def self.all - @all ||= generate_subclasses - end - - def self.generate_subclasses - IssueCustomField.all.map do |field| - class_name = class_name_for field.name - CostQuery::GroupBy.send(:remove_const, class_name) if CostQuery::GroupBy.const_defined? class_name - CostQuery::GroupBy.const_set class_name, Class.new(self).prepare(field, class_name) - end - end - - def self.prepare(field, class_name) - label field.name - table_name(class_name.demodulize.underscore.tableize) - dont_inherit :group_fields - group_fields table_name - join_table(<<-SQL % [CustomValue.table_name, table_name, field.id, field.name]) - -- BEGIN Custom Field Join: "%4$s" - LEFT OUTER JOIN ( - SELECT - value AS %2$s, - customized_type, - custom_field_id, - customized_id - FROM - %1$s) - AS %2$s - ON %2$s.customized_type = 'Issue' - AND %2$s.custom_field_id = %3$d - AND %2$s.customized_id = entries.issue_id - -- END Custom Field Join: "%4$s" - SQL - self - end - - def self.new(*) - fail "Only subclasses of #{self} should be instanciated." unless self < CustomField - super - end - - def self.class_name_for(field) - "CustomField" << field.split(/[ \-_]/).map { |part| part.gsub(/\W/, '').capitalize }.join - end + extend CustomFieldMixin + on_prepare { group_fields table_name } end end diff --git a/app/models/cost_query/inherited_attribute.rb b/app/models/cost_query/inherited_attribute.rb index 2e4e7a18ad..9fb5f9c34d 100644 --- a/app/models/cost_query/inherited_attribute.rb +++ b/app/models/cost_query/inherited_attribute.rb @@ -28,7 +28,7 @@ module CostQuery::InheritedAttribute alias singleton_class metaclass unless respond_to? :singleton_class def define_singleton_method(name, &block) - attr_writer name + singleton_class.send :attr_writer, name singleton_class.class_eval { define_method(name, &block) } define_method(name) { instance_variable_get("@#{name}") or singleton_class.send(name) } end diff --git a/app/models/cost_query/sql_statement.rb b/app/models/cost_query/sql_statement.rb index 43bf7ee3f3..1bcc0cf6b8 100644 --- a/app/models/cost_query/sql_statement.rb +++ b/app/models/cost_query/sql_statement.rb @@ -154,7 +154,7 @@ class CostQuery::SqlStatement sql = "\n-- BEGIN #{desc}\n" \ "SELECT\n#{select.map { |e| "\t#{e}" }.join ",\n"}" \ "\nFROM\n\t#{from.gsub("\n", "\n\t")}" \ - "\n#{joins.map { |e| "\t#{e}" }.join "\n"}" \ + "\n\t#{joins.map { |e| e.gsub("\n", "\n\t") }.join "\n\t"}" \ "\nWHERE #{where.join " AND "}\n" sql << "GROUP BY #{group_by.join ', '}\nORDER BY #{group_by.join ', '}\n" if group_by? sql << "-- END #{desc}\n"