google_data_source 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/Gemfile +11 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +25 -0
  6. data/Rakefile +31 -0
  7. data/google_data_source.gemspec +32 -0
  8. data/lib/assets/images/google_data_source/chart_bar_add.png +0 -0
  9. data/lib/assets/images/google_data_source/chart_bar_delete.png +0 -0
  10. data/lib/assets/images/google_data_source/loader.gif +0 -0
  11. data/lib/assets/javascripts/google_data_source/data_source_init.js +3 -0
  12. data/lib/assets/javascripts/google_data_source/extended_data_table.js +76 -0
  13. data/lib/assets/javascripts/google_data_source/filter_form.js +180 -0
  14. data/lib/assets/javascripts/google_data_source/google_visualization/combo_table.js.erb +113 -0
  15. data/lib/assets/javascripts/google_data_source/google_visualization/table.js +116 -0
  16. data/lib/assets/javascripts/google_data_source/google_visualization/timeline.js +13 -0
  17. data/lib/assets/javascripts/google_data_source/google_visualization/visualization.js.erb +141 -0
  18. data/lib/assets/javascripts/google_data_source/index.js +7 -0
  19. data/lib/dummy_engine.rb +5 -0
  20. data/lib/google_data_source.rb +33 -0
  21. data/lib/google_data_source/base.rb +281 -0
  22. data/lib/google_data_source/column.rb +31 -0
  23. data/lib/google_data_source/csv_data.rb +23 -0
  24. data/lib/google_data_source/data_date.rb +17 -0
  25. data/lib/google_data_source/data_date_time.rb +17 -0
  26. data/lib/google_data_source/helper.rb +69 -0
  27. data/lib/google_data_source/html_data.rb +6 -0
  28. data/lib/google_data_source/invalid_data.rb +14 -0
  29. data/lib/google_data_source/json_data.rb +78 -0
  30. data/lib/google_data_source/railtie.rb +36 -0
  31. data/lib/google_data_source/sql/models.rb +266 -0
  32. data/lib/google_data_source/sql/parser.rb +239 -0
  33. data/lib/google_data_source/sql_parser.rb +82 -0
  34. data/lib/google_data_source/template_handler.rb +31 -0
  35. data/lib/google_data_source/test_helper.rb +26 -0
  36. data/lib/google_data_source/version.rb +3 -0
  37. data/lib/google_data_source/xml_data.rb +25 -0
  38. data/lib/locale/de.yml +5 -0
  39. data/lib/reporting/action_controller_extension.rb +19 -0
  40. data/lib/reporting/grouped_set.rb +58 -0
  41. data/lib/reporting/helper.rb +110 -0
  42. data/lib/reporting/reporting.rb +352 -0
  43. data/lib/reporting/reporting_adapter.rb +27 -0
  44. data/lib/reporting/reporting_entry.rb +147 -0
  45. data/lib/reporting/sql_reporting.rb +220 -0
  46. data/test/lib/empty_reporting.rb +2 -0
  47. data/test/lib/test_reporting.rb +33 -0
  48. data/test/lib/test_reporting_b.rb +9 -0
  49. data/test/lib/test_reporting_c.rb +3 -0
  50. data/test/locales/en.models.yml +6 -0
  51. data/test/locales/en.reportings.yml +5 -0
  52. data/test/rails/reporting_renderer_test.rb +47 -0
  53. data/test/test_helper.rb +50 -0
  54. data/test/units/base_test.rb +340 -0
  55. data/test/units/csv_data_test.rb +36 -0
  56. data/test/units/grouped_set_test.rb +60 -0
  57. data/test/units/json_data_test.rb +68 -0
  58. data/test/units/reporting_adapter_test.rb +20 -0
  59. data/test/units/reporting_entry_test.rb +149 -0
  60. data/test/units/reporting_test.rb +374 -0
  61. data/test/units/sql_parser_test.rb +111 -0
  62. data/test/units/sql_reporting_test.rb +307 -0
  63. data/test/units/xml_data_test.rb +32 -0
  64. metadata +286 -0
@@ -0,0 +1,36 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+
3
+ class CvsDataTest < ActiveSupport::TestCase
4
+ def setup
5
+ setup_db
6
+ end
7
+
8
+ def teardown
9
+ teardown_db
10
+ end
11
+
12
+ test "csv rendering" do
13
+ items = [Item.create(:name => "Item Name", :description => "description", :number => 0)]
14
+ ds = GoogleDataSource::DataSource::Base.from_params({:tqx => "reqId:0;out:csv"})
15
+
16
+ columns = [
17
+ {:id => 'name', :label => 'Name', :type => 'string'},
18
+ {:id => 'number', :label => 'Number', :type => 'number'},
19
+ ]
20
+ ds.set(items, columns)
21
+
22
+ result = CSV.parse(ds.response, :col_sep => ';')
23
+ assert_equal [["Name", "Number"], ["Item Name", "0"]], result
24
+ end
25
+
26
+ test "number formating" do
27
+ items = [{:int => 1000000, :float => 1000000000.1}]
28
+ ds = GoogleDataSource::DataSource::Base.from_params({:tqx => "reqId:0;out:csv"})
29
+ columns = [
30
+ {:id => 'int', :type => 'number'},
31
+ {:id => 'float', :type => 'number'},
32
+ ]
33
+ ds.set(items, columns)
34
+ #TODO
35
+ end
36
+ end
@@ -0,0 +1,60 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+
3
+ class GroupedSetTest < ActiveSupport::TestCase
4
+ class TestReportingEntry < ReportingEntry
5
+ SUMMABLE_INT_FIELDS_REGEXP = /^(views|clicks|backfill_views|.*transaction_count)$/
6
+ SUMMABLE_FLOAT_FIELDS_REGEXP = /^(.*_sum|.*_sum_after_share)$/
7
+ NOT_SUMMABLE_FIELDS = %w(public_website_name)
8
+ end
9
+
10
+ setup do
11
+ entries = []
12
+ entries << TestReportingEntry.new({:date => Date.today.to_s(:db), :unit_id => "1", :ad_id => "1", :open_sum => "1" })
13
+ entries << TestReportingEntry.new({:date => Date.today.to_s(:db), :unit_id => "2", :ad_id => "1", :open_sum => "2" })
14
+ entries << TestReportingEntry.new({:date => Date.today.to_s(:db), :unit_id => "1", :ad_id => "2", :open_sum => "4" })
15
+ entries << TestReportingEntry.new({:date => Date.today.to_s(:db), :unit_id => "2", :ad_id => "2", :open_sum => "8" })
16
+ entries << TestReportingEntry.new({:date => 1.day.ago.to_s(:db), :unit_id => "1", :ad_id => "1", :open_sum => "16" })
17
+
18
+ @set = GroupedSet.new(entries)
19
+ end
20
+
21
+ test "should group by single key" do
22
+ data = @set.regroup(:date)
23
+ assert_equal 2, data.size
24
+ todays_entry = data.select { |e| e.date == Date.today.to_s(:db) }.first
25
+ assert_equal 15.0, todays_entry.open_sum
26
+ end
27
+
28
+ test "should group by multiple keys" do
29
+ data = @set.regroup(:date, :ad_id)
30
+ assert_equal 3, data.size
31
+ todays_ad1_entry = data.select { |e| e.date == Date.today.to_s(:db) && e.ad_id == "1"}.first
32
+ assert_equal 3.0, todays_ad1_entry.open_sum
33
+ end
34
+
35
+ test "should group by block" do
36
+ data = @set.regroup { |e| e.date }
37
+ assert_equal 2, data.size
38
+ todays_entry = data.select { |e| e.date == Date.today.to_s(:db) }.first
39
+ assert_equal 15.0, todays_entry.open_sum
40
+ end
41
+
42
+ test "should collapse" do
43
+ data = @set.collapse
44
+ assert_equal 31.0, data.open_sum
45
+ end
46
+
47
+ test "something interesting" do
48
+ result = [
49
+ {"campaign_name"=>"Campaign #5", "billing_subject"=>'foo', "campaign_id"=>"8188", "transaction_count"=>"2", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"45.3000001907349", "status"=>"confirmed", "pricing_association_id"=>"330"},
50
+ {"campaign_name"=>"Campaign #6", "billing_subject"=>'blah', "campaign_id"=>"8189", "transaction_count"=>"1", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"1.10000002384186", "status"=>"confirmed", "pricing_association_id"=>"330"},
51
+ {"campaign_name"=>"Campaign #6", "billing_subject"=>'blah', "campaign_id"=>"8189", "transaction_count"=>"1", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"1.10000002384186", "status"=>"open", "pricing_association_id"=>"330"},
52
+ {"campaign_name"=>"Campaign #6", "billing_subject"=>"test", "campaign_id"=>"8189", "transaction_count"=>"1", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"31337", "status"=>"open", "pricing_association_id"=>"330"}
53
+ ]
54
+ result.collect!{ |re| TestReportingEntry.new(re) }
55
+ result = GroupedSet.new(result)
56
+ result = result.regroup('campaign_id', 'billing_subject')
57
+ assert_equal %w(foo blah test), result.collect(&:billing_subject)
58
+ assert_equal 3, result.size
59
+ end
60
+ end
@@ -0,0 +1,68 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+
3
+ class JsonDataTest < ActiveSupport::TestCase
4
+ context 'The JSON Data output engine' do
5
+ setup do
6
+ setup_db
7
+ end
8
+
9
+ teardown do
10
+ teardown_db
11
+ end
12
+
13
+ setup do
14
+ @items = [
15
+ Item.create(
16
+ :name => "Item Name",
17
+ :description => "description",
18
+ :number => 0,
19
+ :date => '2011-01-01',
20
+ :datetime => '2011-01-01 23:59:59'
21
+ ),
22
+ Item.create(
23
+ :name => "Item Name",
24
+ :description => "description",
25
+ :number => 10,
26
+ :date => nil,
27
+ :datetime => nil
28
+ )
29
+ ]
30
+ @datasource = GoogleDataSource::DataSource::Base.from_params({:tqx => "reqId:0;out:json"})
31
+
32
+ @columns = [
33
+ {:id => 'name', :label => 'Name', :type => 'string'},
34
+ {:id => 'number', :label => 'Number', :type => 'number'},
35
+ {:id => 'date', :label => 'Date', :type => 'date'},
36
+ {:id => 'datetime', :label => 'Datetime', :type => 'datetime'},
37
+ ]
38
+ @datasource.set(@items, @columns)
39
+ @raw_json = @datasource.response.match(/\{(.*)\}/)[0].gsub("\\\\", "\\");
40
+ @json = JSON.parse(@raw_json)
41
+ end
42
+
43
+ should "correctly render a json record" do
44
+ assert_equal 'Item Name', @json['table']['rows'].first.first.last[0]['v']
45
+ end
46
+
47
+ should "render an integer" do
48
+ assert_equal 0, @json['table']['rows'].first.first.last[1]['v']
49
+ assert_equal 10, @json['table']['rows'].last.first.last[1]['v']
50
+ end
51
+
52
+ should "correctly render a datetime value" do
53
+ assert_equal 'Date(2011, 0, 1, 23, 59, 59)', @json['table']['rows'].first.first.last[3]['v']
54
+ end
55
+
56
+ should "corretly render an empty datetime" do
57
+ assert_equal nil, @json['table']['rows'].last.first.last[3]['v']
58
+ end
59
+
60
+ should "correctly render a date value" do
61
+ assert_equal 'Date(2011, 0, 1)', @json['table']['rows'].first.first.last[2]['v']
62
+ end
63
+
64
+ should "corretly render an empty date" do
65
+ assert_equal nil, @json['table']['rows'].last.first.last[3]['v']
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+
3
+ class ReportingAdapterTest < ActiveSupport::TestCase
4
+ setup do
5
+ @adapter = ActiveRecord::ConnectionAdapters::ReportingAdapter.new
6
+ end
7
+
8
+ test "quote a single quote with a backslash" do
9
+ assert_equal "'foo\\''", @adapter.quote('foo\'')
10
+ end
11
+
12
+ test "return integers as quoted boolean" do
13
+ assert_equal "'1'", @adapter.quoted_true
14
+ assert_equal "'0'", @adapter.quoted_false
15
+ end
16
+
17
+ test "quote a backslash with a backslash" do
18
+ assert_equal "'foo\\\\'", @adapter.quote("foo\\")
19
+ end
20
+ end
@@ -0,0 +1,149 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+
3
+ class ReportingEntryTest < ActiveSupport::TestCase
4
+ class TestReportingEntry < ReportingEntry
5
+ SUMMABLE_INT_FIELDS_REGEXP = /int|another_value/
6
+ SUMMABLE_FLOAT_FIELDS_REGEXP = /float/
7
+ NOT_SUMMABLE_FIELDS = %w(hide_me)
8
+
9
+ def reduced
10
+ int - 1
11
+ end
12
+
13
+ def another_value
14
+ return 1
15
+ end
16
+
17
+ def hide_me
18
+ "I'm not shown in sum entry"
19
+ end
20
+
21
+ def show_me
22
+ "I'm shown!"
23
+ end
24
+ end
25
+
26
+ def setup
27
+ end
28
+
29
+ test "OpenStrcut like access" do
30
+ entry = TestReportingEntry.new(:foo => 'bar')
31
+ assert_equal 'bar', entry.foo
32
+ end
33
+
34
+ test "NoMethodError when attribute is not set" do
35
+ entry = TestReportingEntry.new()
36
+ assert_raise NoMethodError do
37
+ entry.foo
38
+ end
39
+ end
40
+
41
+ test "int values casting" do
42
+ entry = TestReportingEntry.new(:int => "1")
43
+ assert_equal 1, entry.int
44
+ assert entry.int.is_a?(Integer)
45
+ end
46
+
47
+ test "float values casting" do
48
+ entry = TestReportingEntry.new(:float => "1.5")
49
+ assert_equal 1.5, entry.float
50
+ assert entry.float.is_a?(Float)
51
+ end
52
+
53
+ test "accessors for numeric values should return 0 if the values are not defined" do
54
+ entry = TestReportingEntry.new
55
+ assert_equal 0, entry.int
56
+ assert_equal 0.0, entry.float
57
+ end
58
+
59
+ test "the + method should add up all numeric values while merging all others" do
60
+ entry1 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
61
+ entry2 = TestReportingEntry.new(:int => 2, :float => 2.5, :foo => 'bar')
62
+ sum = entry1 + entry2
63
+
64
+ assert_equal 3, sum.int
65
+ assert_equal 4.0, sum.float
66
+ assert_equal 'bar', sum.foo
67
+ end
68
+
69
+ test "the composite entry should also support a working + method" do
70
+ entry1 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
71
+ entry2 = TestReportingEntry.new(:int => 2, :float => 2.5, :foo => 'bar')
72
+ entry3 = TestReportingEntry.new(:int => 3, :float => 3.5, :foo => 'bar')
73
+ sum = entry1 + entry2 + entry3
74
+
75
+ assert_equal 6, sum.int
76
+ assert_equal 7.5, sum.float
77
+ end
78
+
79
+ test "virtual attributes should also work an composite entries" do
80
+ entry1 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
81
+ entry2 = TestReportingEntry.new(:int => 2, :float => 2.5, :foo => 'bar')
82
+
83
+ assert_equal 0, entry1.reduced
84
+ sum = entry1 + entry2
85
+ assert_equal 2, sum.reduced
86
+ end
87
+
88
+ test "to_sum_entry should only set numerical values and strip all others" do
89
+ entry = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
90
+ sum_entry = entry.to_sum_entry
91
+
92
+ assert_nil sum_entry.foo
93
+ assert_equal 1, sum_entry.int
94
+ assert_equal 1.5, sum_entry.float
95
+ end
96
+
97
+ test "to_sum_entry on composite entries" do
98
+ entry1 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
99
+ entry2 = TestReportingEntry.new(:int => 2, :float => 2.5, :foo => 'bar')
100
+ sum = (entry1 + entry2).to_sum_entry
101
+
102
+ assert_nil sum.foo
103
+ assert_equal 3, sum.int
104
+ end
105
+
106
+ test 'to_sum_entry should not return any explicitely hidden ruby columns' do
107
+ entry1 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
108
+ entry2 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
109
+ assert_equal nil, (entry1 + entry2).to_sum_entry.hide_me
110
+ end
111
+
112
+ test 'to_sum_entry should return all ruby columns in sum entry by default' do
113
+ entry1 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
114
+ entry2 = TestReportingEntry.new(:int => 1, :float => 1.5, :foo => 'bar')
115
+ assert_equal "I'm shown!", (entry1 + entry2).to_sum_entry.show_me
116
+ end
117
+
118
+ test "handle summable virtual attributes correclty" do
119
+ entry1 = TestReportingEntry.new()
120
+ entry2 = TestReportingEntry.new()
121
+ sum = entry1 + entry2
122
+
123
+ assert_equal 1, entry1.another_value
124
+ assert_equal 2, sum.another_value
125
+ end
126
+
127
+ test "be able to group by billing_subject" do
128
+ result = [
129
+ {"campaign_name"=>"Campaign #5", "billing_subject"=>'foo', "campaign_id"=>"8188", "transaction_count"=>"2", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"45.3000001907349", "status"=>"confirmed", "pricing_association_id"=>"330"},
130
+ {"campaign_name"=>"Campaign #6", "billing_subject"=>'blah', "campaign_id"=>"8189", "transaction_count"=>"1", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"1.10000002384186", "status"=>"confirmed", "pricing_association_id"=>"330"},
131
+ {"campaign_name"=>"Campaign #6", "billing_subject"=>'blah', "campaign_id"=>"8189", "transaction_count"=>"1", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"1.10000002384186", "status"=>"open", "pricing_association_id"=>"330"},
132
+ {"campaign_name"=>"Campaign #6", "billing_subject"=>"test", "campaign_id"=>"8189", "transaction_count"=>"1", "postview_transaction_count"=>"0", "click_transaction_count"=>"0", "sum"=>"31337", "status"=>"open", "pricing_association_id"=>"330"}
133
+ ]
134
+ result.collect!{ |re| ReportingEntry.new(re) }
135
+ result = result.group_by { |entry| "#{entry.send(:billing_subject)}" }.values
136
+ assert_equal 3, result.size
137
+
138
+ result = result.collect do |entries|
139
+ # Uses the class of the first element to build the composite element
140
+ entries.first.class.composite(entries)
141
+ end
142
+
143
+ assert_equal %w(foo blah test), result.collect(&:billing_subject)
144
+ end
145
+
146
+ test "virtual attributes " do
147
+ assert true
148
+ end
149
+ end
@@ -0,0 +1,374 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+ require "test_reporting"
3
+ require "test_reporting_b"
4
+ require "test_reporting_c"
5
+ require "empty_reporting"
6
+
7
+ class ReportingTest < ActiveSupport::TestCase
8
+ def setup
9
+ @reporting = TestReporting.new
10
+ end
11
+
12
+ test "should return the columns hash, activerecord like" do
13
+ columns_hash = TestReporting.columns_hash
14
+ assert columns_hash.kind_of?(Hash), 'should be a hash'
15
+ assert_equal 'name', columns_hash.keys.first
16
+ end
17
+
18
+ test 'should return all column names' do
19
+ columns = ["name", "age", "address", "fullname", "fullfullname", "circle_a", "circle_b", "from_date", "to_date", "in_foo"]
20
+ assert_equal columns, TestReporting.column_names
21
+ end
22
+
23
+ test "should be able to use the accessors as expected" do
24
+ @reporting.name = 'test'
25
+ assert_equal 'test', @reporting.name
26
+ end
27
+
28
+ test "should return a hash with all default values" do
29
+ defaults = TestReporting.column_defaults
30
+ assert_equal 'foobar', defaults['name'], 'has a default value for name'
31
+ assert_equal nil, defaults['age'], 'has no default value for age'
32
+ end
33
+
34
+ test "rows should call aggregate once and only once" do
35
+ @reporting.data
36
+ @reporting.data
37
+ assert_equal 1, @reporting.aggregate_calls
38
+ end
39
+
40
+ test "should return true if the object is filterable through given column" do
41
+ assert ! @reporting.filterable_by?(:age), 'should not be filterable by normal columns'
42
+ assert @reporting.filterable_by?(:name), 'should be filterable even if the filter was defined as column before'
43
+ assert @reporting.filterable_by?(:from_date), 'should be filterable'
44
+ assert @reporting.filterable_by?('from_date'), 'should be filterable even if a string is given'
45
+ end
46
+
47
+ test "should have a seperate hash for filters" do
48
+ assert_equal({ :type => :string, :default => 'foobar' },
49
+ @reporting.class.datasource_filters["name"],
50
+ 'should be filterable by name')
51
+ end
52
+
53
+ test "from_params should typecast a date correctly" do
54
+ query = "where name = 'test name' and from_date = '2010-01-01'"
55
+ r = TestReporting.from_params({:tq => query})
56
+ assert_equal "test name", r.name
57
+ assert_equal "2010-01-01".to_date, r.from_date
58
+ end
59
+
60
+ test "select default value" do
61
+ r = TestReporting.new
62
+ assert_equal %w(name age), r.select
63
+ end
64
+
65
+ test "group by default value" do
66
+ r = TestReporting.new
67
+ assert_equal %w(name), r.group_by
68
+ end
69
+
70
+ test "limit by default value" do
71
+ r = TestReporting.new
72
+ assert_equal 1000, r.limit
73
+
74
+ r = TestReporting.new(:limit => 5)
75
+ assert_equal 5, r.limit
76
+
77
+ r = TestReporting.new(:limit => "10")
78
+ assert_equal 10, r.limit
79
+ end
80
+
81
+ test "from_params should set select" do
82
+ query = "select name"
83
+ r = TestReporting.from_params({:tq => query})
84
+ assert_equal ['name'], r.select
85
+ end
86
+
87
+ test "select should explode a * column" do
88
+ query = "select *"
89
+ r = TestReporting.from_params({:tq => query})
90
+ r.add_virtual_column(:virtual)
91
+
92
+ select = %w(name age address fullname fullfullname circle_a circle_b virtual)
93
+ assert_equal select, r.select
94
+ end
95
+
96
+ test "from_parmas should set group_by" do
97
+ query = "select name group by name"
98
+ r = TestReporting.from_params({:tq => query})
99
+ assert_equal ['name'], r.group_by
100
+ end
101
+
102
+ test 'should return groupable columns' do
103
+ reporting = TestReporting.new
104
+ assert_equal [ :age, :address ], reporting.groupable_columns
105
+ end
106
+
107
+ test "from_params should also take regular get parameters (not the query) into account" do
108
+ params = HashWithIndifferentAccess.new({:tq => '', :test_reporting => {:name => 'John'}})
109
+ r = TestReporting.from_params(params, 'test_reporting')
110
+ assert_equal "John", r.name
111
+ end
112
+
113
+ test "from_params should also take regular get parameters into account (with custom param name)" do
114
+ params = HashWithIndifferentAccess.new({:tq => '', :reporting => {:name => 'John'}})
115
+ r = TestReporting.from_params(params, :reporting)
116
+ assert_equal "John", r.name
117
+ end
118
+
119
+ test "from_params_with_date_range" do
120
+ query = "where `date` >= '2010-01-01' and `date`<='2010-02-01'"
121
+ r = TestReporting.from_params({:tq => query})
122
+ assert_equal "2010-01-01".to_date, r.from_date
123
+ assert_equal "2010-02-01".to_date, r.to_date
124
+ end
125
+
126
+ test "setting datasource columns" do
127
+ assert_equal :string, @reporting.datasource_columns['name'][:type]
128
+ assert_equal :string, TestReporting.datasource_columns['name'][:type]
129
+ end
130
+
131
+ test "get column definitions with respect to custom column labels and select" do
132
+ columns = @reporting.columns
133
+ assert_equal 2, columns.size
134
+ assert_equal 'name', columns[0][:id]
135
+ assert_equal :string, columns[0][:type]
136
+ end
137
+
138
+ test "different subclasses can have different sets of columns" do
139
+ assert TestReporting.datasource_columns != TestReportingB.datasource_columns
140
+ end
141
+
142
+ test "different subclasses can have different default selects and groupings" do
143
+ a = TestReporting.new
144
+ b = TestReportingB.new
145
+ assert a.group_by != b.group_by
146
+ assert a.select != b.select
147
+ end
148
+
149
+ test "sublasses should inherit all columns" do
150
+ reporting = TestReportingB.new
151
+ assert_nothing_raised do
152
+ assert reporting.datasource_columns.include?('name')
153
+ assert reporting.datasource_columns.include?('name_b')
154
+ end
155
+ end
156
+
157
+ test "subclasses should inherit all filters" do
158
+ assert_equal 5, TestReportingB.datasource_filters.count
159
+ end
160
+
161
+ test "subclasses should inherit all defaults" do
162
+ reporting = TestReportingC.new
163
+ assert_nothing_raised do
164
+ assert_equal ["name", "age"], reporting.defaults[:select]
165
+ end
166
+ end
167
+
168
+ test "should set limit and offset in from_params" do
169
+ reporting = TestReporting.from_params(:tq => "limit 10 offset 5")
170
+ assert_equal 10, reporting.limit
171
+ assert_equal 5, reporting.offset
172
+ reporting = TestReporting.from_params("query" => { "limit" => "10", "offset" => "5" })
173
+ assert_equal 10, reporting.limit
174
+ assert_equal 5, reporting.offset
175
+ end
176
+
177
+ test "should set the order_by attribute in from_params" do
178
+ reporting = TestReporting.from_params(:tq => "order by name")
179
+ assert_equal ['name', :asc], reporting.order_by
180
+ end
181
+
182
+ test "should return nil for order by and offset if not set" do
183
+ reporting = TestReporting.new
184
+ assert_nil reporting.order_by
185
+ #assert_nil reporting.limit
186
+ assert_nil reporting.offset
187
+ end
188
+
189
+ test "parse in( ) statement and put in 'in_xxx' attribute" do
190
+ reporting = TestReporting.from_params(:tq => "where foo in (1, 2)")
191
+ assert_equal %w(1 2), reporting.in_foo
192
+ end
193
+
194
+ test "translation of column labels" do
195
+ assert_equal 'AgeReportings', @reporting.column_label(:age)
196
+ assert_equal 'AddressModels', @reporting.column_label(:address)
197
+ end
198
+
199
+ test "the rows method should accept a reqired_columns option" do
200
+ @reporting.select = %w(age)
201
+ @reporting.group_by = []
202
+ assert_equal %w(age), @reporting.required_columns
203
+ @reporting.data(:required_columns => %w(name))
204
+ assert_equal %w(age name), @reporting.required_columns
205
+ end
206
+
207
+ test "serialization and deserialization" do
208
+ @reporting.select = %w(age)
209
+ @reporting.group_by = %w(age)
210
+ @reporting.order_by = %w(name)
211
+ @reporting.limit = 10
212
+ @reporting.offset = 20
213
+ @reporting.name = "John"
214
+
215
+ serialized = @reporting.serialize
216
+ reporting = TestReporting.deserialize(serialized)
217
+
218
+ assert_equal @reporting.select, reporting.select
219
+ assert_equal @reporting.group_by, reporting.group_by
220
+ assert_equal @reporting.order_by, reporting.order_by
221
+ assert_equal @reporting.limit, reporting.limit
222
+ assert_equal @reporting.offset, reporting.offset
223
+ assert_equal @reporting.name, reporting.name
224
+ end
225
+
226
+ test "from_params should recognize a serialized object and deserialize it" do
227
+ @reporting.select = %w(age)
228
+ @reporting.group_by = %w(age)
229
+ @reporting.name = "John"
230
+ serialized = @reporting.serialize
231
+ reporting = TestReporting.from_params(@reporting.to_params)
232
+
233
+ assert_equal @reporting.select, reporting.select
234
+ assert_equal @reporting.group_by, reporting.group_by
235
+ assert_equal @reporting.name, reporting.name
236
+ end
237
+
238
+ test 'from_params should accept a hash without a module name' do
239
+ reporting = TestReporting.from_params('test_reporting' => { 'select' => %w(age) })
240
+ assert_equal %w(age), reporting.select
241
+ end
242
+
243
+ test 'from_params from param "query" should work as well' do
244
+ reporting = TestReporting.from_params('query' => { 'name' => 'bla' })
245
+ assert_equal 'bla', reporting.name
246
+ end
247
+
248
+ test 'accept a "page" param and calculate the offset' do
249
+ reporting = TestReporting.from_params('query' => { 'page' => '3' })
250
+ assert reporting.limit.is_a?(Integer)
251
+ assert reporting.offset.is_a?(Integer)
252
+ assert_equal reporting.limit * 2, reporting.offset
253
+ end
254
+
255
+ test 'to_params should export the hash with a module name by default' do
256
+ assert_equal %w(test_reporting), @reporting.to_params.keys
257
+ end
258
+
259
+ test "initialize should handle date string with grace" do
260
+ reporting = TestReporting.new(:from_date => '2010-01-01')
261
+ assert_equal Date.parse('2010-01-01'), reporting.from_date
262
+ end
263
+
264
+ test "account for the 'requires' option in column definition" do
265
+ reporting = TestReporting.new
266
+ reporting.select = %w(fullname)
267
+ reporting.group_by = []
268
+ result = reporting.required_columns
269
+ assert_equal 2, result.size
270
+ assert result.include?('name')
271
+ assert result.include?('fullname')
272
+ end
273
+
274
+ test "'requires' option in column definition should work recursivly" do
275
+ reporting = TestReporting.new
276
+ reporting.select = %w(fullfullname)
277
+ reporting.group_by = []
278
+ result = reporting.required_columns
279
+ assert_equal 3, result.size
280
+ assert result.include?('name')
281
+ assert result.include?('fullname')
282
+ assert result.include?('fullfullname')
283
+ end
284
+
285
+ test "recognize circle dependencies in column and throw exception" do
286
+ reporting = TestReporting.new
287
+ reporting.select = %w(circle_a)
288
+ reporting.group_by = []
289
+ assert_raise CircularDependencyException do
290
+ reporting.required_columns
291
+ end
292
+ end
293
+
294
+ test "required_columns should handle virtual columns with grace" do
295
+ reporting = TestReporting.new
296
+ reporting.select = %w(virtual_column name)
297
+ assert_equal %w(virtual_column name), reporting.required_columns
298
+ end
299
+
300
+ ################################
301
+ # Test ActiveRecord extension
302
+ ################################
303
+
304
+ test "class loads" do
305
+ assert_nothing_raised { Reporting }
306
+ end
307
+
308
+ test "can add columns" do
309
+ self.class.class_eval %q{
310
+ class CanAddColumns < Reporting
311
+ %w(foo bar test).each { |c| column c }
312
+ end
313
+ }
314
+ assert_equal 3, CanAddColumns.columns.size
315
+ end
316
+
317
+ test "type properly set" do
318
+ self.class.class_eval %q{
319
+ class TypeProperlySet < Reporting
320
+ %w(string text date datetime boolean).each do |type|
321
+ filter "a_#{type}".to_sym, :type => type.to_sym
322
+ end
323
+ end
324
+ }
325
+
326
+ assert TypeProperlySet.columns.size > 0, 'no filters added'
327
+
328
+ %w(string text date datetime boolean).each do |type|
329
+ assert_equal type, TypeProperlySet.columns_hash["a_#{type}"].sql_type
330
+ end
331
+ end
332
+
333
+ test "default properly set" do
334
+ self.class.class_eval %q{
335
+ class DefaultPropertlySet < Reporting
336
+ filter :bicycle, :default => 'batavus'
337
+ end
338
+ }
339
+ assert_equal 'batavus', DefaultPropertlySet.new.bicycle
340
+ end
341
+
342
+ test "columns are humanizable" do
343
+ self.class.class_eval %q{
344
+ class Humanizable < Reporting
345
+ filter :bicycle, :human_name => 'fiets'
346
+ end
347
+ }
348
+
349
+ assert_equal 'fiets', Humanizable.columns_hash['bicycle'].humanize
350
+ end
351
+
352
+ test "create gbang raises no exception on valid" do
353
+ self.class.class_eval %q{
354
+ class CreateBangSuccess < Reporting; end
355
+ }
356
+
357
+ assert_nothing_raised do
358
+ CreateBangSuccess.create!
359
+ end
360
+ end
361
+
362
+ test "create bang raises exception on invalid" do
363
+ self.class.class_eval %q{
364
+ class CreateBangFailure < Reporting
365
+ filter :required_field
366
+ validates_presence_of :required_field
367
+ end
368
+ }
369
+
370
+ assert_raises ActiveRecord::RecordInvalid do
371
+ CreateBangFailure.create!
372
+ end
373
+ end
374
+ end