google_data_source 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|