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,111 @@
1
+ # coding: utf-8
2
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
3
+
4
+ class SqlParserTest < ActiveSupport::TestCase
5
+ include GoogleDataSource::DataSource
6
+
7
+ test "quoting with ticks" do
8
+ result = SqlParser.parse("where `foo bar`=3")
9
+ assert_equal 'foo bar', result.where.left.to_s
10
+ end
11
+
12
+ test "quoting with single quotes" do
13
+ result = SqlParser.parse("where bar='foo bar'")
14
+ assert_equal 'foo bar', result.where.right.to_s
15
+ end
16
+
17
+ test "allow escaped quotes in qutoed strings" do
18
+ result = SqlParser.parse("where bar='test\\''")
19
+ assert_equal "test'", result.where.right.to_s
20
+ end
21
+
22
+ test "allow escaped backslash" do
23
+ result = SqlParser.parse("where bar='te\\\\st'")
24
+ assert_equal "te\\st", result.where.right.to_s
25
+ end
26
+
27
+ test "allow escaped backslash as last character" do
28
+ result = SqlParser.parse("where bar='test\\\\'")
29
+ assert_equal "test\\", result.where.right.to_s
30
+ end
31
+
32
+ test "parsing of empty single quoted string ('')" do
33
+ result = SqlParser.parse("where foo=''")
34
+ assert_equal "", result.where.right.to_s
35
+ end
36
+
37
+ test "the 'in' statement in where conditions" do
38
+ result = SqlParser.parse("where foo in ('1','2')")
39
+ assert_equal "foo", result.where.expr.to_s
40
+ assert_equal 2, result.where.vals.size
41
+ assert_equal '1', result.where.vals[0].to_s
42
+ assert_equal '2', result.where.vals[1].to_s
43
+ end
44
+
45
+ ###############################
46
+ # Test the simple parser
47
+ ###############################
48
+ test "simple parser" do
49
+ result = SqlParser.simple_parse("select id,name where age = 18 group by attr1, attr2 order by age asc limit 10 offset 5")
50
+ assert_equal ['id', 'name'], result.select
51
+ assert_equal 10, result.limit
52
+ assert_equal 5, result.offset
53
+ assert_equal ['attr1', 'attr2'], result.groupby
54
+ assert_equal ['age', :asc], result.orderby
55
+ assert_equal({'age' => '18'}, result.conditions)
56
+ end
57
+
58
+ test "simple order parser should only accept a single ordering" do
59
+ assert_raises GoogleDataSource::DataSource::SimpleSqlException do
60
+ SqlParser.simple_parse("order by name,date")
61
+ end
62
+ end
63
+
64
+ test "simple groupby parser should return empty array if no group by statement is given" do
65
+ assert_equal [], SqlParser.simple_parse("").groupby
66
+ end
67
+
68
+ test "simple where parser" do
69
+ conditions = SqlParser.simple_parse("where id = 1 and name = `foo bar` and `foo bar` = 123").conditions
70
+
71
+ assert_equal '1', conditions['id']
72
+ assert_equal 'foo bar', conditions['name']
73
+ assert_equal '123', conditions['foo bar']
74
+ end
75
+
76
+ test "simple where parser should only accept and operators" do
77
+ assert_raises GoogleDataSource::DataSource::SimpleSqlException do
78
+ SqlParser.simple_parse("where id = 1 or name = `foo bar`")
79
+ end
80
+ end
81
+
82
+ test "where parser should convert other operators than = to array" do
83
+ conditions = SqlParser.simple_parse("where date > '2010-01-01' and date < '2010-02-01'").conditions
84
+ assert_kind_of Array, conditions['date']
85
+ assert_equal '>', conditions['date'].first.op
86
+ assert_equal '2010-01-01', conditions['date'].first.value
87
+ assert_equal '<', conditions['date'].last.op
88
+ assert_equal '2010-02-01', conditions['date'].last.value
89
+ end
90
+
91
+ test "limit should be nil if empty in query" do
92
+ assert_nil SqlParser.simple_parse("").limit
93
+ end
94
+
95
+ test "offset should be nil if empty in query" do
96
+ assert_nil SqlParser.simple_parse("").offset
97
+ end
98
+
99
+ test "raise exception if operator = is used besides of other operators in where clause" do
100
+ assert_raise GoogleDataSource::DataSource::SimpleSqlException do
101
+ SqlParser.simple_parse("where foo = '1' and foo >= 2")
102
+ end
103
+ end
104
+
105
+ test "parsing in( ) expressions in where clause" do
106
+ conditions = SqlParser.simple_parse("where foo in ('1','2')").conditions
107
+ assert_equal 1, conditions['foo'].size
108
+ assert_equal 'in', conditions['foo'].first.op
109
+ assert_equal %w(1 2), conditions['foo'].first.value
110
+ end
111
+ end
@@ -0,0 +1,307 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+ require "lib/empty_reporting"
3
+
4
+ class SqlReportingTest < ActiveSupport::TestCase
5
+ class SqlTestReporting < SqlReporting
6
+ attr_reader :aggregate_calls
7
+ filter :name, :sql => true
8
+ filter :lastname
9
+ filter :got_no_sql_column
10
+ filter :building_no, :type => :number
11
+ filter :test_integer, :type => :integer
12
+ filter :boolean_thing, :type => :boolean, :sql => true
13
+
14
+ table :notneeded, :join => 'JOIN notneeded'
15
+ table :buildings, :depends => :companies, :join => 'JOIN buildings'
16
+ table :companies, :join => 'JOIN companies'
17
+
18
+ column :firstname, :type => :string, :sql => true
19
+ column :lastname, :type => :string, :sql => { :column => :name }
20
+ column :company_name, :type => :string, :sql => { :table => :companies, :column => :name }
21
+ column :fullname, :type => :string
22
+ column :building_no, :type => :number, :sql => { :table => :buildings, :column => :number }
23
+ column :literal_column, :type => :string, :sql => { :table => :companies, :column => 'literal' }
24
+
25
+ column :info, :type => :string, :requires => :firstname
26
+ column :boolean_thing, :type => :boolean, :sql => { :table => :companies, :column => :my_boolean }
27
+
28
+ def initialize(*args)
29
+ @aggregate_calls = 0
30
+ super(*args)
31
+ end
32
+
33
+ def aggregate
34
+ @aggregate_calls += 1
35
+ @rows = []
36
+ end
37
+ end
38
+
39
+ class SqlTestReportingB < SqlTestReporting
40
+ filter :name_b
41
+ end
42
+
43
+ class SqlTestReportingC < SqlTestReporting
44
+ table :dummy
45
+ end
46
+
47
+ class EmptySqlTestReporting < SqlReporting
48
+
49
+ # overridden for testability
50
+ def self.column(name, options = {})
51
+ @defined_columns ||= {}
52
+ @defined_columns.merge!({name => options})
53
+ end
54
+
55
+ def self.defined_columns
56
+ @defined_columns
57
+ end
58
+ end
59
+
60
+
61
+ def setup
62
+ @reporting = SqlTestReporting.new
63
+ end
64
+
65
+ test 'should mark bind variables as used columns' do
66
+ reporting = SqlTestReporting.new(:name => 'foo', :lastname => 'bar')
67
+ assert_equal([], reporting.columns_used)
68
+ reporting.mark_used_columns
69
+ assert_equal([ :name ], reporting.columns_used)
70
+ end
71
+
72
+ test 'should return an array of bind variables for the query' do
73
+ assert_equal({ :name => 'foo' }, SqlTestReporting.new(:name => 'foo', :lastname => 'bar').sql_bind_variables)
74
+ end
75
+
76
+ test 'should return an array of sql conditions concatinated by AND, and mark colums as used' do
77
+ reporting = SqlTestReporting.new(:name => 'foo', :boolean_thing => true)
78
+ conditions = reporting.sql_conditions
79
+ assert_equal "(name = 'foo') AND (companies.my_boolean = '1')", conditions
80
+ assert_equal [:name, :boolean_thing], reporting.columns_used
81
+ end
82
+
83
+ test 'should return a condition for a boolean field' do
84
+ assert_equal "(companies.my_boolean = '1')", @reporting.sql_condition_for(:boolean_thing, true)
85
+ assert_equal "(companies.my_boolean = '0' OR ISNULL(companies.my_boolean))", @reporting.sql_condition_for(:boolean_thing, false)
86
+ end
87
+
88
+ test 'should return a condition for a number field' do
89
+ assert_equal "(buildings.number = 1 )", @reporting.sql_condition_for(:building_no, 1)
90
+ assert_equal '(buildings.number = \'1\' )', @reporting.sql_condition_for(:building_no, '1')
91
+ assert_equal '(buildings.number = \'0\' OR ISNULL(buildings.number))', @reporting.sql_condition_for(:building_no, '0')
92
+ assert_equal '(buildings.number = 0 OR ISNULL(buildings.number))', @reporting.sql_condition_for(:building_no, 0)
93
+ end
94
+
95
+ test 'should return a condition for an integer field' do
96
+ assert_equal '(test_integer = 0 OR ISNULL(test_integer))', @reporting.sql_condition_for(:test_integer, 0)
97
+ end
98
+ test 'should return a condition for a string field' do
99
+ assert_equal '(name = \'foobar\')', @reporting.sql_condition_for(:lastname, 'foobar')
100
+ end
101
+
102
+ test 'should safely handle quotes in escaped value' do
103
+ assert_equal '(name = \'"test"\')', @reporting.sql_condition_for(:lastname, '"test"')
104
+ assert_equal "(name = '\\'test\\'')", @reporting.sql_condition_for(:lastname, "'test'")
105
+ end
106
+
107
+ test "should return an array with values as IN match" do
108
+ assert_equal "(name IN('test','test2'))", @reporting.sql_condition_for(:lastname, %w(test test2))
109
+ end
110
+
111
+ test 'should return a condition even if there is no sql column defined for this filter' do
112
+ assert_equal '(got_no_sql_column = \'foobar\')', @reporting.sql_condition_for(:got_no_sql_column, 'foobar')
113
+ end
114
+
115
+ test "is_sql_column?" do
116
+ assert @reporting.is_sql_column?(:firstname), 'should be an sql column'
117
+ assert @reporting.is_sql_column?('lastname'), 'should be an sql column'
118
+ assert !@reporting.is_sql_column?(:fullname), 'should be no sql column'
119
+ end
120
+
121
+ test "sql_column_name" do
122
+ assert !@reporting.sql_column_name(:fullname)
123
+ assert_equal 'firstname', @reporting.sql_column_name(:firstname)
124
+ assert_equal 'firstname', @reporting.sql_column_name(:firstname, :with_alias => true)
125
+ assert_equal 'name', @reporting.sql_column_name(:lastname)
126
+ assert_equal 'companies.name', @reporting.sql_column_name(:company_name)
127
+ assert_equal 'companies.name company_name', @reporting.sql_column_name(:company_name, :with_alias => true)
128
+ end
129
+
130
+ test "select should consider mapping" do
131
+ @reporting.select = %w(firstname)
132
+ assert_equal 'christian_name firstname', @reporting.sql_select([], 'firstname' => 'christian_name')
133
+ end
134
+
135
+ test "group_by should consider mapping" do
136
+ @reporting.group_by = %w(firstname)
137
+ assert_equal 'christian_name', @reporting.sql_group_by([], 'firstname' => 'christian_name')
138
+ end
139
+
140
+ test "select some sql and some ruby columns" do
141
+ reporting = reporting_from_query("select firstname, fullname")
142
+ assert_equal "firstname", reporting.sql_select
143
+ end
144
+
145
+ test "use column name mappings in sql_select" do
146
+ reporting = reporting_from_query("select company_name, fullname")
147
+ assert_equal "companies.name company_name", reporting.sql_select
148
+ end
149
+
150
+ test "sql_columns" do
151
+ assert @reporting.sql_columns.include?(:firstname)
152
+ assert @reporting.sql_columns.include?(:company_name)
153
+ assert !@reporting.sql_columns.include?(:fullname)
154
+ end
155
+
156
+ test "select *" do
157
+ reporting = reporting_from_query("select *")
158
+ sql = reporting.sql_columns.collect { |c| reporting.sql_column_name(c, :with_alias => true) }.join (', ')
159
+ assert_equal sql, reporting.sql_select
160
+ end
161
+
162
+ test "sql_group_by" do
163
+ reporting = reporting_from_query("group by firstname, fullname")
164
+ assert_equal "firstname", reporting.sql_group_by
165
+ end
166
+
167
+ test "sql_group_by should be nil if no grouping exists" do
168
+ reporting = reporting_from_query("")
169
+ assert_nil reporting.sql_group_by
170
+ end
171
+
172
+ test "sql_order_by should return nil if the column is a virtual one" do
173
+ reporting = reporting_from_query("order by fullname")
174
+ assert_nil reporting.sql_order_by
175
+ end
176
+
177
+ test "sql_order_by" do
178
+ reporting = reporting_from_query("order by firstname")
179
+ assert_equal "firstname ASC", reporting.sql_order_by
180
+ end
181
+
182
+ test "sql_order_by shoul consider mapping" do
183
+ reporting = reporting_from_query("order by firstname")
184
+ assert_equal "name ASC", reporting.sql_order_by('firstname' => 'name')
185
+ end
186
+
187
+ test "sql_order_by should return nil if order_by is not set" do
188
+ reporting = reporting_from_query("")
189
+ assert_nil reporting.sql_order_by
190
+ end
191
+
192
+ test "use column name mappings in sql_group_by" do
193
+ reporting = reporting_from_query("group by firstname, lastname, fullname")
194
+ assert_equal "firstname, name", reporting.sql_group_by
195
+ end
196
+
197
+ test "get joins for columns" do
198
+ assert_equal "", @reporting.sql_joins(%w(firstname))
199
+ assert_equal "JOIN companies", @reporting.sql_joins(%w(company_name))
200
+ end
201
+
202
+ test "get joins resolving dependencies" do
203
+ assert_equal "JOIN companies JOIN buildings", @reporting.sql_joins(%w(building_no company_name))
204
+ end
205
+
206
+ test "columns method should return plain columns without sql option" do
207
+ reporting = reporting_from_query("select *")
208
+ reporting.columns.each do |column|
209
+ assert !column.has_key?(:sql)
210
+ end
211
+ end
212
+
213
+ test "join according to the used columns" do
214
+ reporting = reporting_from_query("select firstname")
215
+ assert_equal "", reporting.sql_joins
216
+
217
+ reporting = reporting_from_query("select company_name")
218
+ reporting.sql_select
219
+ assert_equal "JOIN companies", reporting.sql_joins
220
+ end
221
+
222
+ test "join if columns are added with mark_as_used" do
223
+ reporting = reporting_from_query("select firstname")
224
+ assert_equal "", reporting.sql_joins
225
+ reporting.mark_as_used('company_name')
226
+ assert_equal "JOIN companies", reporting.sql_joins
227
+ end
228
+
229
+ test "include required columns in sql_select statement" do
230
+ reporting = reporting_from_query("select firstname")
231
+ reporting.add_required_columns :company_name
232
+ select = reporting.sql_select.split(', ')
233
+ assert_equal 2, select.size
234
+ assert select.include?('firstname')
235
+ assert select.include?('companies.name company_name')
236
+ end
237
+
238
+ test "account for columns that require other columns" do
239
+ reporting = reporting_from_query("select info")
240
+ select = reporting.sql_select.split(', ')
241
+ assert_equal 1, select.size
242
+ assert_equal 'firstname', select.first
243
+ end
244
+
245
+ test "include joins for required columns" do
246
+ reporting = reporting_from_query("select firstname")
247
+ reporting.add_required_columns :company_name
248
+ assert_equal "JOIN companies", reporting.sql_joins
249
+ end
250
+
251
+ test "sql_group_by should recognize the mapping if it's the first parameter" do
252
+ @reporting.group_by = %w(firstname)
253
+ assert_equal "christian_name", @reporting.sql_group_by('firstname' => 'christian_name')
254
+ end
255
+
256
+ test "should not append table name if column name is give as string" do
257
+ assert_equal 'literal', @reporting.sql_column_name(:literal_column)
258
+ end
259
+
260
+ test "subclasses should inherit sql_tables" do
261
+ assert_equal 3, SqlTestReporting.sql_tables.count
262
+ assert_equal 3, SqlTestReportingB.sql_tables.count
263
+ assert_equal 4, SqlTestReportingC.sql_tables.count
264
+ end
265
+
266
+ test "model_columns should find names and types" do
267
+ assert_equal( {:first_col => :number, :second_col => :string, :third_col => :dummy_type},
268
+ SqlReporting::model_columns(model_mock) )
269
+ end
270
+
271
+ test "add_sql_columns_for should add all columns" do
272
+ EmptySqlTestReporting::expects(:model_columns).with("dummy_object").
273
+ returns({:first_col => :string, :second_col => :number})
274
+
275
+ EmptySqlTestReporting::add_sql_columns_for("dummy_object")
276
+
277
+ assert_equal( {
278
+ :first_col => {:type => :string, :sql => true, :grouping => true},
279
+ :second_col => {:type => :number, :sql => {:column=>"SUM(second_col)"}, :grouping => false}
280
+ }, EmptySqlTestReporting.defined_columns)
281
+ end
282
+
283
+ test "add_sql_columns_for should add all but the excluded columns" do
284
+ EmptySqlTestReporting::expects(:model_columns).with("dummy_object").
285
+ returns({:first_col => :string, :second_col => :number})
286
+
287
+ EmptySqlTestReporting::add_sql_columns_for("dummy_object", :except => ["second_col"])
288
+
289
+ assert_equal( {
290
+ :first_col => {:type => :string, :sql => true, :grouping => true}
291
+ }, EmptySqlTestReporting.defined_columns)
292
+ end
293
+
294
+ protected
295
+
296
+ def reporting_from_query(query)
297
+ SqlTestReporting.from_params({:tq => query})
298
+ end
299
+
300
+ def model_mock
301
+ number_mock = OpenStruct.new(:number? => true)
302
+ string_mock = OpenStruct.new(:number? => false, :text? => true)
303
+ other_mock = OpenStruct.new(:number? => false, :text? => false, :type => :dummy_type)
304
+
305
+ OpenStruct.new(:columns_hash => {:first_col => number_mock, :second_col => string_mock, :third_col => other_mock})
306
+ end
307
+ end
@@ -0,0 +1,32 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper"
2
+
3
+ class XmlDataTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ setup_db
7
+ end
8
+
9
+ def teardown
10
+ teardown_db
11
+ end
12
+
13
+ test "xml rendering" do
14
+ items = [Item.create(:name => "Item Name 1", :description => "hidden description", :number => 0),
15
+ Item.create(:name => "Item Name 2", :description => "description", :number => 1)]
16
+ ds = GoogleDataSource::DataSource::Base.from_params({:tqx => "reqId:0;out:xml"})
17
+
18
+ columns = [
19
+ {:id => 'name', :label => 'Name', :type => 'string'},
20
+ {:id => 'number', :label => 'Number', :type => 'number'},
21
+ ]
22
+ ds.set(items, columns)
23
+
24
+ xml = Nokogiri::XML(ds.response)
25
+
26
+ assert xml.xml?
27
+ assert_equal 2, xml.root.css('item').size
28
+ assert_equal 'Item Name 1', xml.root.css('item name').first.child.inner_text
29
+ assert_equal 0, xml.errors.size
30
+ end
31
+
32
+ end