google_data_source 0.7.6

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