From a50a812bc1b9bb1ab3584d03afbf773084bfd10f Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Mon, 18 Apr 2011 11:07:02 +0200 Subject: [PATCH 1/7] Manipulate query directly in sql_statement for testing purposes. --- lib/report/sql_statement.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/report/sql_statement.rb b/lib/report/sql_statement.rb index 3c73f708a6..e14efaba1d 100644 --- a/lib/report/sql_statement.rb +++ b/lib/report/sql_statement.rb @@ -72,6 +72,18 @@ class Report::SqlStatement # @return [String] The query def to_s # FIXME I'm ugly + #select("CASE WHEN COUNT(*) >= 10 THEN '10+' ELSE COUNT(*) END as number_of_assessments") + + #select("(CASE WHEN users.number_of_assessments >= 10 THEN 10 ELSE users.number_of_assessments END) as number_of_assessments") + #unselect("users.number_of_assessments") + + #group_by("number_of_assessments") + + #group_not_by("users.sector_id") + #group_by("number_of_assessments") + #group_not_by("users.number_of_assessments") + #group_by("users.sector_id") + @sql ||= begin sql = "\n-- BEGIN #{desc}\n" \ "SELECT\n#{select.map { |e| "\t#{e}" }.join ",\n"}" \ @@ -192,6 +204,13 @@ class Report::SqlStatement end end + def unselect(*fields) + @sql = nil + @select = @select.reject do |field| + fields.find { |f| f == field } + end + end + ## # Return the names which have been bound through select statements # @return [Array] All fields for select part @@ -220,6 +239,13 @@ class Report::SqlStatement end end + def group_not_by(*fields) + @sql = nil + @group_by = @group_by.reject do |field| + fields.find { |f| f == field } + end + end + ## # @return [TrueClass, FalseClass] Whether or not to add a group by part. def group_by? From b212b2f2826e941027ff91d6eb0c82a6de18160e Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Mon, 18 Apr 2011 15:43:36 +0200 Subject: [PATCH 2/7] hacked sql statement for partition --- lib/report/sql_statement.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/report/sql_statement.rb b/lib/report/sql_statement.rb index e14efaba1d..69e54b240a 100644 --- a/lib/report/sql_statement.rb +++ b/lib/report/sql_statement.rb @@ -74,15 +74,15 @@ class Report::SqlStatement # FIXME I'm ugly #select("CASE WHEN COUNT(*) >= 10 THEN '10+' ELSE COUNT(*) END as number_of_assessments") - #select("(CASE WHEN users.number_of_assessments >= 10 THEN 10 ELSE users.number_of_assessments END) as number_of_assessments") - #unselect("users.number_of_assessments") + select("(CASE WHEN users.number_of_assessments >= 10 THEN 10 ELSE users.number_of_assessments END) as number_of_assessments") + unselect("users.number_of_assessments") #group_by("number_of_assessments") - #group_not_by("users.sector_id") - #group_by("number_of_assessments") - #group_not_by("users.number_of_assessments") - #group_by("users.sector_id") + group_not_by("users.sector_id") + group_by("number_of_assessments") + group_not_by("users.number_of_assessments") + group_by("users.sector_id") @sql ||= begin sql = "\n-- BEGIN #{desc}\n" \ From eb45137c82e7afa4779b14ab8de297db336a5436 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Wed, 20 Apr 2011 16:53:38 +0200 Subject: [PATCH 3/7] removed debug hack --- lib/report/sql_statement.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/report/sql_statement.rb b/lib/report/sql_statement.rb index 69e54b240a..160cd2d317 100644 --- a/lib/report/sql_statement.rb +++ b/lib/report/sql_statement.rb @@ -72,18 +72,6 @@ class Report::SqlStatement # @return [String] The query def to_s # FIXME I'm ugly - #select("CASE WHEN COUNT(*) >= 10 THEN '10+' ELSE COUNT(*) END as number_of_assessments") - - select("(CASE WHEN users.number_of_assessments >= 10 THEN 10 ELSE users.number_of_assessments END) as number_of_assessments") - unselect("users.number_of_assessments") - - #group_by("number_of_assessments") - - group_not_by("users.sector_id") - group_by("number_of_assessments") - group_not_by("users.number_of_assessments") - group_by("users.sector_id") - @sql ||= begin sql = "\n-- BEGIN #{desc}\n" \ "SELECT\n#{select.map { |e| "\t#{e}" }.join ",\n"}" \ From 9ff9b1694822873876c89ccf44198893b808d96f Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Wed, 20 Apr 2011 16:54:17 +0200 Subject: [PATCH 4/7] Introduced #never_select and #never_group_by. --- lib/report/sql_statement.rb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/report/sql_statement.rb b/lib/report/sql_statement.rb index 160cd2d317..9dd20c80f4 100644 --- a/lib/report/sql_statement.rb +++ b/lib/report/sql_statement.rb @@ -174,7 +174,7 @@ class Report::SqlStatement return(@select || default_select) if fields.empty? (@select ||= []).tap do @sql = nil - fields.each do |f| + fields.reject {|f| never_select.include? f}.each do |f| case f when Array if f.size == 2 and f.first.respond_to? :table_name then select field_name_for(f) @@ -199,6 +199,15 @@ class Report::SqlStatement end end + def never_select(*fields) + (@never_select ||= []).tap do + unless fields.empty? + @never_select += fields + unselect *fields + end + end + end + ## # Return the names which have been bound through select statements # @return [Array] All fields for select part @@ -216,7 +225,7 @@ class Report::SqlStatement def group_by(*fields) @sql = nil unless fields.empty? (@group_by ||= []).tap do - fields.each do |e| + fields.reject {|f| never_group_by.include? f}.each do |e| if e.is_a? Array and (e.size != 2 or !e.first.respond_to? :table_name) group_by(*e) else @@ -234,6 +243,15 @@ class Report::SqlStatement end end + def never_group_by(*fields) + (@never_group_by ||= []).tap do + unless fields.empty? + @never_group_by += fields + group_not_by *fields + end + end + end + ## # @return [TrueClass, FalseClass] Whether or not to add a group by part. def group_by? From 16511e0127b296c0fe69b7bdb656447b308ff129 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Wed, 27 Apr 2011 18:50:17 +0200 Subject: [PATCH 5/7] hard-coded partitioning on ruby side --- lib/report/result.rb | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/report/result.rb b/lib/report/result.rb index 5b34fc3a48..11d7cab014 100644 --- a/lib/report/result.rb +++ b/lib/report/result.rb @@ -40,7 +40,33 @@ class Report::Result data = group_by do |entry| # index for group is a hash # i.e. { :foo => 10, :bar => 20 } <= this is just the KEY!!!! - fields.inject({}) { |hash, key| hash.merge key => entry.fields[key] } + fields.inject({}) do |hash, key| + val = entry.fields[key] + if key =~ /^number_of.*/ + if val.to_i >= 10 + val = "10+" + end + end + hash.merge key => val # entry.fields[key] + end + end + if data.keys.size > 0 + num = data.keys[0].keys.find { |key| key =~ /^number_of.*/ } + data.keys.find_all { |key| key[num].to_i >= 10 }.each do |key| + unique_results = [] + data[key].each do |result| + pkey = result.fields.except num, "count" + if (tuple = unique_results.find { |t| t[0] == pkey }) + ures = tuple[1] + ures.fields["count"] = (ures.fields["count"].to_i + result.fields["count"].to_i).to_s + else + ures = result + ures.fields[num] = "10+" + unique_results << [pkey, ures] + end + end + data[key] = unique_results.collect { |tuple| tuple[1] } + end end # map group back to array, all fields with same key get grouped into one list data.keys.map { |f| engine::Result.new data[f], f, type, important_fields } From cd714170285f16aaabe9e8a37de49261687a7f5c Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Wed, 27 Apr 2011 19:15:16 +0200 Subject: [PATCH 6/7] moved partitioning into extra method. Made it work with several number_of-group-bys. @TODO move to UR. --- lib/report/result.rb | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/report/result.rb b/lib/report/result.rb index 11d7cab014..cf115bd9e0 100644 --- a/lib/report/result.rb +++ b/lib/report/result.rb @@ -50,24 +50,7 @@ class Report::Result hash.merge key => val # entry.fields[key] end end - if data.keys.size > 0 - num = data.keys[0].keys.find { |key| key =~ /^number_of.*/ } - data.keys.find_all { |key| key[num].to_i >= 10 }.each do |key| - unique_results = [] - data[key].each do |result| - pkey = result.fields.except num, "count" - if (tuple = unique_results.find { |t| t[0] == pkey }) - ures = tuple[1] - ures.fields["count"] = (ures.fields["count"].to_i + result.fields["count"].to_i).to_s - else - ures = result - ures.fields[num] = "10+" - unique_results << [pkey, ures] - end - end - data[key] = unique_results.collect { |tuple| tuple[1] } - end - end + partition(data) # map group back to array, all fields with same key get grouped into one list data.keys.map { |f| engine::Result.new data[f], f, type, important_fields } end @@ -76,6 +59,30 @@ class Report::Result engine::Result.new list, {}, type, important_fields end + def partition(data, skip_keys=[]) + if data.keys.size > 0 + num = data.keys[0].keys.find { |key| !skip_keys.include?(key) and key =~ /^number_of.*/ } + if num + data.keys.find_all { |key| key[num].to_i >= 10 }.each do |key| + unique_results = [] + data[key].each do |result| + pkey = result.fields.except num, "count" + if (tuple = unique_results.find { |t| t[0] == pkey }) + ures = tuple[1] + ures.fields["count"] = (ures.fields["count"].to_i + result.fields["count"].to_i).to_s + else + ures = result + ures.fields[num] = "10+" + unique_results << [pkey, ures] + end + end + data[key] = unique_results.collect { |tuple| tuple[1] } + end + partition(data, skip_keys + [num]) + end + end + end + def inspect "<##{self.class}: @fields=#{fields.inspect} @type=#{type.inspect} " \ "@size=#{size} @count=#{count} @units=#{units}>" From 9d072b59cdcb3c517d46e321c90fb15064cb8d69 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Thu, 28 Apr 2011 15:55:07 +0200 Subject: [PATCH 7/7] introduced 'hooks' for partitioning and moved actual logic into UR --- lib/report/result.rb | 53 ++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/lib/report/result.rb b/lib/report/result.rb index cf115bd9e0..97ee2773a1 100644 --- a/lib/report/result.rb +++ b/lib/report/result.rb @@ -31,6 +31,24 @@ class Report::Result fields[key] end + ## + # Override if you want to influence the result grouping. + # + # @return A value for grouping or nil if the given field should + # not be considered for grouping. + def map_group_by_value(key, value) + value + end + + ## + # This method is called when this result is requested as #grouped_by something + # just before the result is returned. + # + # @param data This result's grouped data. + def group_by_data_ready(data) + # good to know! + end + def grouped_by(fields, type, important_fields = []) @grouped_by ||= {} list = begin @@ -41,16 +59,11 @@ class Report::Result # index for group is a hash # i.e. { :foo => 10, :bar => 20 } <= this is just the KEY!!!! fields.inject({}) do |hash, key| - val = entry.fields[key] - if key =~ /^number_of.*/ - if val.to_i >= 10 - val = "10+" - end - end - hash.merge key => val # entry.fields[key] + val = map_group_by_value(key, entry.fields[key]) + hash.merge key => val end end - partition(data) + group_by_data_ready(data) # map group back to array, all fields with same key get grouped into one list data.keys.map { |f| engine::Result.new data[f], f, type, important_fields } end @@ -59,30 +72,6 @@ class Report::Result engine::Result.new list, {}, type, important_fields end - def partition(data, skip_keys=[]) - if data.keys.size > 0 - num = data.keys[0].keys.find { |key| !skip_keys.include?(key) and key =~ /^number_of.*/ } - if num - data.keys.find_all { |key| key[num].to_i >= 10 }.each do |key| - unique_results = [] - data[key].each do |result| - pkey = result.fields.except num, "count" - if (tuple = unique_results.find { |t| t[0] == pkey }) - ures = tuple[1] - ures.fields["count"] = (ures.fields["count"].to_i + result.fields["count"].to_i).to_s - else - ures = result - ures.fields[num] = "10+" - unique_results << [pkey, ures] - end - end - data[key] = unique_results.collect { |tuple| tuple[1] } - end - partition(data, skip_keys + [num]) - end - end - end - def inspect "<##{self.class}: @fields=#{fields.inspect} @type=#{type.inspect} " \ "@size=#{size} @count=#{count} @units=#{units}>"