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.
- data/.document +5 -0
- data/.gitignore +7 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +25 -0
- data/Rakefile +31 -0
- data/google_data_source.gemspec +32 -0
- data/lib/assets/images/google_data_source/chart_bar_add.png +0 -0
- data/lib/assets/images/google_data_source/chart_bar_delete.png +0 -0
- data/lib/assets/images/google_data_source/loader.gif +0 -0
- data/lib/assets/javascripts/google_data_source/data_source_init.js +3 -0
- data/lib/assets/javascripts/google_data_source/extended_data_table.js +76 -0
- data/lib/assets/javascripts/google_data_source/filter_form.js +180 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/combo_table.js.erb +113 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/table.js +116 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/timeline.js +13 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/visualization.js.erb +141 -0
- data/lib/assets/javascripts/google_data_source/index.js +7 -0
- data/lib/dummy_engine.rb +5 -0
- data/lib/google_data_source.rb +33 -0
- data/lib/google_data_source/base.rb +281 -0
- data/lib/google_data_source/column.rb +31 -0
- data/lib/google_data_source/csv_data.rb +23 -0
- data/lib/google_data_source/data_date.rb +17 -0
- data/lib/google_data_source/data_date_time.rb +17 -0
- data/lib/google_data_source/helper.rb +69 -0
- data/lib/google_data_source/html_data.rb +6 -0
- data/lib/google_data_source/invalid_data.rb +14 -0
- data/lib/google_data_source/json_data.rb +78 -0
- data/lib/google_data_source/railtie.rb +36 -0
- data/lib/google_data_source/sql/models.rb +266 -0
- data/lib/google_data_source/sql/parser.rb +239 -0
- data/lib/google_data_source/sql_parser.rb +82 -0
- data/lib/google_data_source/template_handler.rb +31 -0
- data/lib/google_data_source/test_helper.rb +26 -0
- data/lib/google_data_source/version.rb +3 -0
- data/lib/google_data_source/xml_data.rb +25 -0
- data/lib/locale/de.yml +5 -0
- data/lib/reporting/action_controller_extension.rb +19 -0
- data/lib/reporting/grouped_set.rb +58 -0
- data/lib/reporting/helper.rb +110 -0
- data/lib/reporting/reporting.rb +352 -0
- data/lib/reporting/reporting_adapter.rb +27 -0
- data/lib/reporting/reporting_entry.rb +147 -0
- data/lib/reporting/sql_reporting.rb +220 -0
- data/test/lib/empty_reporting.rb +2 -0
- data/test/lib/test_reporting.rb +33 -0
- data/test/lib/test_reporting_b.rb +9 -0
- data/test/lib/test_reporting_c.rb +3 -0
- data/test/locales/en.models.yml +6 -0
- data/test/locales/en.reportings.yml +5 -0
- data/test/rails/reporting_renderer_test.rb +47 -0
- data/test/test_helper.rb +50 -0
- data/test/units/base_test.rb +340 -0
- data/test/units/csv_data_test.rb +36 -0
- data/test/units/grouped_set_test.rb +60 -0
- data/test/units/json_data_test.rb +68 -0
- data/test/units/reporting_adapter_test.rb +20 -0
- data/test/units/reporting_entry_test.rb +149 -0
- data/test/units/reporting_test.rb +374 -0
- data/test/units/sql_parser_test.rb +111 -0
- data/test/units/sql_reporting_test.rb +307 -0
- data/test/units/xml_data_test.rb +32 -0
- 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
|