ruport 0.6.0 → 0.6.1
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/AUTHORS +4 -0
- data/CHANGELOG +10 -1
- data/Rakefile +1 -1
- data/examples/simple_table_interface.rb +20 -0
- data/lib/ruport.rb +87 -69
- data/lib/ruport/attempt.rb +1 -1
- data/lib/ruport/config.rb +198 -166
- data/lib/ruport/data.rb +6 -1
- data/lib/ruport/data/collection.rb +15 -8
- data/lib/ruport/data/groupable.rb +68 -6
- data/lib/ruport/data/record.rb +73 -34
- data/lib/ruport/data/record.rb~ +236 -0
- data/lib/ruport/data/set.rb +48 -13
- data/lib/ruport/data/table.rb +164 -74
- data/lib/ruport/data/table.rb.rej +67 -0
- data/lib/ruport/data/table.rb~ +153 -68
- data/lib/ruport/data/taggable.rb +37 -9
- data/lib/ruport/format.rb +1 -1
- data/lib/ruport/mailer.rb +41 -27
- data/lib/ruport/meta_tools.rb +26 -11
- data/lib/ruport/query.rb +102 -68
- data/lib/ruport/query/sql_split.rb +1 -1
- data/lib/ruport/report.rb +84 -58
- data/lib/ruport/report/graph.rb +1 -1
- data/lib/ruport/report/invoice.rb +1 -1
- data/test/test_query.rb +305 -48
- data/test/test_query.rb.rej +161 -0
- data/test/test_query.rb~ +337 -0
- data/test/test_record.rb +6 -0
- data/test/test_table.rb +18 -0
- data/test/test_table.rb~ +336 -0
- data/test/unit.log +180 -6
- metadata +8 -2
data/lib/ruport/report.rb
CHANGED
@@ -29,7 +29,7 @@ module Ruport
|
|
29
29
|
# require "ruport"
|
30
30
|
# require "fileutils"
|
31
31
|
# class MyReport < Ruport::Report
|
32
|
-
# prepare
|
32
|
+
# def prepare
|
33
33
|
# log_file "f.log"
|
34
34
|
# log "preparing report", :status => :info
|
35
35
|
# source :default,
|
@@ -40,12 +40,12 @@ module Ruport
|
|
40
40
|
# :address => "gregory.t.brown@gmail.com"
|
41
41
|
# end
|
42
42
|
#
|
43
|
-
# generate
|
43
|
+
# def generate
|
44
44
|
# log "generated csv from query", :status => :info
|
45
45
|
# query "select * from bar", :as => :csv
|
46
46
|
# end
|
47
47
|
#
|
48
|
-
# cleanup
|
48
|
+
# def cleanup
|
49
49
|
# log "removing foo.csv", :status => :info
|
50
50
|
# FileUtils.rm("foo.csv")
|
51
51
|
# end
|
@@ -63,24 +63,26 @@ module Ruport
|
|
63
63
|
# }
|
64
64
|
#
|
65
65
|
#
|
66
|
-
# This class can also be used to run templates and process text filters
|
66
|
+
# This class can also be used to run templates and process text filters.
|
67
67
|
#
|
68
68
|
# See the examples in the documentation below to see how to use these
|
69
|
-
# features
|
70
|
-
# Report#eval_template
|
69
|
+
# features (namely Report#process_text , Report#text_processor, and
|
70
|
+
# Report#eval_template).
|
71
71
|
#
|
72
72
|
class Report
|
73
73
|
extend Forwardable
|
74
74
|
|
75
75
|
include Ruport::Data::TableHelper
|
76
|
+
#
|
76
77
|
# When initializing a report, you can provide a default mailer and source by
|
77
78
|
# giving a name of a valid source or mailer you've defined via
|
78
|
-
# Ruport::Config
|
79
|
+
# Ruport::Config.
|
79
80
|
#
|
80
81
|
# If your report does not need any sort of specialized information, you can
|
81
|
-
# simply use Report.run (Or MyReportName.run if you've inherited)
|
82
|
+
# simply use Report.run (Or MyReportName.run if you've inherited).
|
82
83
|
#
|
83
84
|
# This will auto-initialize a report.
|
85
|
+
#
|
84
86
|
def initialize( source_name=:default, mailer_name=:default )
|
85
87
|
use_source source_name
|
86
88
|
use_mailer mailer_name
|
@@ -89,46 +91,49 @@ module Ruport
|
|
89
91
|
@file = nil
|
90
92
|
end
|
91
93
|
|
92
|
-
#
|
94
|
+
# By default, this file will be used by Report#write.
|
93
95
|
attr_accessor :file
|
94
96
|
|
95
|
-
#
|
96
|
-
#
|
97
|
+
#
|
98
|
+
# This attribute will get the results of Report#generate when the report is
|
99
|
+
# run.
|
100
|
+
#
|
97
101
|
attr_accessor :results
|
98
102
|
|
99
|
-
#
|
103
|
+
# This is a simplified interface to Ruport::Query.
|
100
104
|
#
|
101
|
-
#
|
105
|
+
# You can use it to read SQL statements from file or string:
|
102
106
|
#
|
103
|
-
#
|
104
|
-
#
|
107
|
+
# #from string
|
108
|
+
# result = query "select * from foo"
|
105
109
|
#
|
106
|
-
#
|
107
|
-
#
|
110
|
+
# #from file
|
111
|
+
# result = query "my_query.sql", :origin => :file
|
108
112
|
#
|
109
|
-
#
|
113
|
+
# You can use multistatement SQL:
|
110
114
|
#
|
111
|
-
#
|
112
|
-
#
|
115
|
+
# # will return the value of the last statement, "select * from foo"
|
116
|
+
# result = query "insert into foo values(1,2); select * from foo"
|
113
117
|
#
|
114
|
-
#
|
118
|
+
# You can iterate by row or return the entire set:
|
115
119
|
#
|
116
|
-
#
|
120
|
+
# query("select * from foo", :yield_type => :by_row) { |r|
|
117
121
|
# #do something with the rows here
|
118
|
-
#
|
122
|
+
# }
|
119
123
|
#
|
120
|
-
#
|
124
|
+
# query() can return raw DBI:Row objects or Ruport's data structures:
|
121
125
|
#
|
122
|
-
#
|
123
|
-
#
|
126
|
+
# # will return an Array of DBI::Row objects
|
127
|
+
# result = query "select * from foo", :raw_data => true
|
124
128
|
#
|
125
|
-
#
|
129
|
+
# You can quickly output in a number of formats:
|
126
130
|
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
131
|
+
# result = query "select * from foo", :as => :csv
|
132
|
+
# result = query "select * from foo", :as => :html
|
133
|
+
# result = query "select * from foo", :as => :pdf
|
134
|
+
#
|
135
|
+
# See Ruport::Query for details.
|
130
136
|
#
|
131
|
-
# See source of this function and methods of Ruport::Query for details.
|
132
137
|
def query(sql, options={})
|
133
138
|
options[:origin] ||= :string
|
134
139
|
options[:source] ||= @source
|
@@ -143,25 +148,28 @@ module Ruport
|
|
143
148
|
end
|
144
149
|
end
|
145
150
|
|
146
|
-
# Evaluates _code_ from _filename_ as pure ruby code for files ending in
|
147
|
-
# .rb, and as ERb templates for anything else.
|
148
151
|
#
|
149
|
-
#
|
150
|
-
#
|
152
|
+
# Evaluates <tt>code</tt> from <tt>filename</tt> as pure ruby code for
|
153
|
+
# files ending in .rb, and as ERb templates for anything else.
|
154
|
+
#
|
155
|
+
# This code will be evaluated in the context of the instance on which it
|
156
|
+
# is called.
|
157
|
+
#
|
151
158
|
def eval_template( code, filename=nil )
|
152
159
|
filename =~ /\.rb/ ? eval(code) : ERB.new(code, 0, "%").result(binding)
|
153
160
|
end
|
154
161
|
|
155
|
-
#
|
162
|
+
# Sets the active source to the Ruport::Config source requested by <tt>label</tt>.
|
156
163
|
def use_source(label)
|
157
164
|
@source = label
|
158
165
|
end
|
159
166
|
|
160
|
-
#
|
167
|
+
# Sets the active mailer to the Ruport::Config source requested by <tt>label</tt>.
|
161
168
|
def use_mailer(label)
|
162
169
|
@mailer = label
|
163
170
|
end
|
164
171
|
|
172
|
+
#
|
165
173
|
# Provides a nice way to execute templates and filters.
|
166
174
|
#
|
167
175
|
# Example:
|
@@ -170,6 +178,7 @@ module Ruport
|
|
170
178
|
#
|
171
179
|
# This method automatically passes a binding into the filters, so you are
|
172
180
|
# free to access data from your Report instance in your templates.
|
181
|
+
#
|
173
182
|
def process_text(string, options)
|
174
183
|
options[:filters].each do |f|
|
175
184
|
format = Format.new(binding)
|
@@ -179,60 +188,70 @@ module Ruport
|
|
179
188
|
string
|
180
189
|
end
|
181
190
|
|
182
|
-
#
|
191
|
+
#
|
192
|
+
# This allows you to create filters to be used by process_text.
|
183
193
|
#
|
184
194
|
# The block is evaluated in the context of the instance.
|
185
195
|
#
|
186
|
-
#
|
196
|
+
# Example:
|
187
197
|
#
|
188
198
|
# text_processor(:unix_newlines) { |r| r.gsub(/\r\n/,"\n") }
|
199
|
+
#
|
189
200
|
def text_processor(label,&block)
|
190
201
|
Format.register_filter(label, &block)
|
191
202
|
end
|
192
203
|
|
193
|
-
|
194
|
-
# Writes the contents of <tt>results</tt> to file. If a filename is
|
204
|
+
#
|
205
|
+
# Writes the contents of <tt>results</tt> to a file. If a filename is
|
195
206
|
# specified, it will use it. Otherwise, it will try to write to the file
|
196
207
|
# specified by the <tt>file</tt> attribute.
|
208
|
+
#
|
197
209
|
def write(my_file=file,my_results=results)
|
198
210
|
File.open(my_file,"w") { |f| f << my_results }
|
199
211
|
end
|
200
212
|
|
213
|
+
#
|
201
214
|
# Like Report#write, but will append to a file rather than overwrite it if
|
202
|
-
# the file already exists
|
215
|
+
# the file already exists.
|
216
|
+
#
|
203
217
|
def append(my_file=file)
|
204
218
|
File.open(my_file,"a") { |f| f << results }
|
205
219
|
end
|
206
220
|
|
207
221
|
class << self
|
208
222
|
|
223
|
+
#
|
209
224
|
# Defines an instance method which will be run before the
|
210
|
-
# <tt>generate</tt> method when Ruport.run is executed
|
225
|
+
# <tt>generate</tt> method when Ruport.run is executed.
|
211
226
|
#
|
212
|
-
# Good for setting config info and perhaps files and/or loggers
|
227
|
+
# Good for setting config info and perhaps files and/or loggers.
|
213
228
|
#
|
214
229
|
def prepare(&block); define_method(:prepare,&block) end
|
215
230
|
|
216
|
-
#
|
231
|
+
#
|
232
|
+
# Defines an instance method which will be executed by Report.run.
|
217
233
|
#
|
218
234
|
# The return value of this method is assigned to the <tt>results</tt>
|
219
|
-
# attribute
|
235
|
+
# attribute.
|
220
236
|
#
|
221
237
|
def generate(&block); define_method(:generate,&block) end
|
222
238
|
|
239
|
+
#
|
223
240
|
# Defines an instance method which will be executed after the object is
|
224
|
-
# yielded in Report.run
|
241
|
+
# yielded in Report.run.
|
225
242
|
#
|
226
243
|
def cleanup(&block); define_method(:cleanup,&block) end
|
227
244
|
|
245
|
+
#
|
228
246
|
# Runs the reports specified. If no reports are specified, then it
|
229
|
-
# creates a new instance via <tt>self.new</tt
|
247
|
+
# creates a new instance via <tt>self.new</tt>.
|
230
248
|
#
|
231
249
|
# Tries to execute the prepare instance method, then runs generate.
|
232
250
|
# It then yields the object so that you may do something with it
|
233
|
-
# (print something out, write to file, email, etc)
|
251
|
+
# (print something out, write to file, email, etc.).
|
234
252
|
#
|
235
253
|
# Finally, it tries to call cleanup.
|
254
|
+
#
|
236
255
|
def run(options={})
|
237
256
|
options[:reports] ||= [self.new]
|
238
257
|
|
@@ -260,23 +279,26 @@ module Ruport
|
|
260
279
|
|
261
280
|
end
|
262
281
|
|
263
|
-
#
|
282
|
+
#
|
283
|
+
# This method passes <tt>self</tt> to Report.run.
|
264
284
|
#
|
265
285
|
# Please see the class method for details.
|
286
|
+
#
|
266
287
|
def run(options={},&block)
|
267
288
|
options[:reports] ||= [self]
|
268
289
|
self.class.run(options,&block)
|
269
290
|
end
|
270
291
|
|
271
|
-
|
272
|
-
# loads a CSV in from file.
|
273
292
|
#
|
274
|
-
#
|
293
|
+
# Loads a CSV in from a file.
|
294
|
+
#
|
295
|
+
# Example:
|
296
|
+
#
|
297
|
+
# my_table = load_csv "foo.csv" #=> Data::Table
|
298
|
+
# my_array = load_csv "foo.csv", :as => :array #=> Array
|
275
299
|
#
|
276
|
-
#
|
277
|
-
# my_array = load_csv "foo.csv", :as => :array #=> Array
|
300
|
+
# See also Ruport::Data::Table.load
|
278
301
|
#
|
279
|
-
# See also, Ruport::Data::Table.load
|
280
302
|
def load_csv(file,options={})
|
281
303
|
case options[:as]
|
282
304
|
when :array
|
@@ -287,11 +309,15 @@ module Ruport
|
|
287
309
|
end
|
288
310
|
end
|
289
311
|
|
290
|
-
#
|
312
|
+
#
|
313
|
+
# Allows logging and other fun stuff.
|
314
|
+
# See also Ruport.log
|
315
|
+
#
|
291
316
|
def log(*args); Ruport.log(*args) end
|
292
317
|
|
318
|
+
#
|
293
319
|
# Creates a new Mailer and sets the <tt>to</tt> attribute to the addresses
|
294
|
-
# specified.
|
320
|
+
# specified. Yields a Mailer object, which can be modified before delivery.
|
295
321
|
#
|
296
322
|
def send_to(adds)
|
297
323
|
m = Mailer.new
|
data/lib/ruport/report/graph.rb
CHANGED
data/test/test_query.rb
CHANGED
@@ -1,80 +1,337 @@
|
|
1
1
|
require "test/unit"
|
2
2
|
require "ruport"
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'mocha'
|
6
|
+
require 'stubba'
|
7
|
+
require 'dbi'
|
8
|
+
rescue LoadError
|
9
|
+
$stderr.puts "Warning: Mocha not found -- skipping some Query tests"
|
10
|
+
end
|
5
11
|
|
12
|
+
class TestQuery < Test::Unit::TestCase
|
6
13
|
def setup
|
7
|
-
|
8
|
-
:
|
14
|
+
@sources = {
|
15
|
+
:default => {
|
16
|
+
:dsn => 'ruport:test', :user => 'greg', :password => 'apple' },
|
17
|
+
:alternative => {
|
18
|
+
:dsn => "ruport:test2", :user => "sandal", :password => "harmonix" },
|
19
|
+
}
|
20
|
+
Ruport::Config.source :default, @sources[:default]
|
21
|
+
Ruport::Config.source :alternative, @sources[:alternative]
|
22
|
+
|
23
|
+
@columns = %w(a b c)
|
24
|
+
@data = [ [[1,2,3],[4,5,6],[7,8,9]],
|
25
|
+
[[9,8,7],[6,5,4],[3,2,1]],
|
26
|
+
[[7,8,9],[4,5,6],[1,2,3]], ]
|
27
|
+
@datasets = @data.dup
|
28
|
+
|
29
|
+
@sql = [ "select * from foo", "create table foo ..." ]
|
30
|
+
@sql << @sql.values_at(0, 0).join(";\n")
|
31
|
+
@sql << @sql.values_at(1, 0).join(";\n")
|
32
|
+
@query = {
|
33
|
+
:plain => Ruport::Query.new(@sql[0]),
|
34
|
+
:sourced => Ruport::Query.new(@sql[0], :source => :alternative),
|
35
|
+
:paramed => Ruport::Query.new(@sql[0], :params => [ 42 ]),
|
36
|
+
:cached => Ruport::Query.new(@sql[0], :cache_enabled => true),
|
37
|
+
:uncached => Ruport::Query.new(@sql[0], :cache_enabled => false),
|
38
|
+
:precached => Ruport::Query.new(@sql[0], :cache_enabled => true),
|
39
|
+
:raw => Ruport::Query.new(@sql[0], :raw_data => true),
|
40
|
+
:unraw => Ruport::Query.new(@sql[0], :raw_data => false),
|
41
|
+
:resultless => Ruport::Query.new(@sql[1]),
|
42
|
+
:multi => Ruport::Query.new(@sql[2]),
|
43
|
+
:mixed => Ruport::Query.new(@sql[3]),
|
44
|
+
}
|
45
|
+
@query[:precached].cached_data = @data[0]
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_execute
|
49
|
+
return unless Object.const_defined? :Mocha
|
50
|
+
query = @query[:uncached]
|
51
|
+
setup_mock_dbi(1)
|
9
52
|
|
10
|
-
|
11
|
-
|
53
|
+
assert_equal nil, query.execute
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_execute_sourced
|
57
|
+
return unless Object.const_defined? :Mocha
|
58
|
+
query = @query[:sourced]
|
59
|
+
setup_mock_dbi(1, :source => :alternative)
|
60
|
+
|
61
|
+
assert_equal nil, query.execute
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_execute_paramed
|
65
|
+
return unless Object.const_defined? :Mocha
|
66
|
+
query = @query[:paramed]
|
67
|
+
setup_mock_dbi(1, :params => [ 42 ])
|
68
|
+
|
69
|
+
assert_equal nil, query.execute
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_result_cache_disabled
|
73
|
+
return unless Object.const_defined? :Mocha
|
74
|
+
query = @query[:uncached]
|
75
|
+
setup_mock_dbi(3)
|
12
76
|
|
13
|
-
|
14
|
-
@
|
77
|
+
assert_nothing_raised { query.result }
|
78
|
+
assert_equal @data[1], get_raw(query.result)
|
79
|
+
assert_equal @data[2], get_raw(query.result)
|
15
80
|
end
|
16
81
|
|
82
|
+
def test_result_cache_enabled
|
83
|
+
return unless Object.const_defined? :Mocha
|
84
|
+
query = @query[:cached]
|
85
|
+
setup_mock_dbi(1)
|
86
|
+
|
87
|
+
assert_nothing_raised { query.result }
|
88
|
+
assert_equal @data[0], get_raw(query.result)
|
89
|
+
assert_equal @data[0], get_raw(query.result)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_result_resultless
|
93
|
+
return unless Object.const_defined? :Mocha
|
94
|
+
query = @query[:resultless]
|
95
|
+
setup_mock_dbi(1, :resultless => true, :sql => @sql[1])
|
96
|
+
|
97
|
+
assert_equal nil, query.result
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_result_multi
|
101
|
+
return unless Object.const_defined? :Mocha
|
102
|
+
query = @query[:multi]
|
103
|
+
setup_mock_dbi(2)
|
104
|
+
|
105
|
+
assert_equal @data[1], get_raw(query.result)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_result_raw_disabled
|
109
|
+
return unless Object.const_defined? :Mocha
|
110
|
+
query = @query[:unraw]
|
111
|
+
setup_mock_dbi(1)
|
112
|
+
|
113
|
+
assert_equal @data[0].to_table(@columns), query.result
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_result_raw_enabled
|
117
|
+
return unless Object.const_defined? :Mocha
|
118
|
+
query = @query[:raw]
|
119
|
+
setup_mock_dbi(1)
|
120
|
+
|
121
|
+
assert_equal @data[0], query.result
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_update_cache
|
125
|
+
return unless Object.const_defined? :Mocha
|
126
|
+
query = @query[:cached]
|
127
|
+
setup_mock_dbi(2)
|
128
|
+
|
129
|
+
assert_equal @data[0], get_raw(query.result)
|
130
|
+
query.update_cache
|
131
|
+
assert_equal @data[1], get_raw(query.cached_data)
|
132
|
+
assert_equal @data[1], get_raw(query.result)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_clear_cache
|
136
|
+
return unless Object.const_defined? :Mocha
|
137
|
+
query = @query[:cached]
|
138
|
+
setup_mock_dbi(2)
|
139
|
+
|
140
|
+
assert_equal @data[0], get_raw(query.result)
|
141
|
+
query.clear_cache
|
142
|
+
assert_equal nil, query.cached_data
|
143
|
+
assert_equal @data[1], get_raw(query.result)
|
144
|
+
end
|
17
145
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
146
|
+
def test_disable_caching
|
147
|
+
return unless Object.const_defined? :Mocha
|
148
|
+
query = @query[:cached]
|
149
|
+
setup_mock_dbi(3)
|
150
|
+
|
151
|
+
assert_equal @data[0], get_raw(query.result)
|
152
|
+
assert_equal @data[0], get_raw(query.result)
|
153
|
+
query.disable_caching
|
154
|
+
assert_equal @data[1], get_raw(query.result)
|
155
|
+
assert_equal @data[2], get_raw(query.result)
|
21
156
|
end
|
22
157
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
158
|
+
def test_enable_caching
|
159
|
+
return unless Object.const_defined? :Mocha
|
160
|
+
query = @query[:uncached]
|
161
|
+
setup_mock_dbi(3)
|
162
|
+
|
163
|
+
assert_equal @data[0], get_raw(query.result)
|
164
|
+
assert_equal @data[1], get_raw(query.result)
|
165
|
+
query.enable_caching
|
166
|
+
assert_equal @data[2], get_raw(query.result)
|
167
|
+
assert_equal @data[2], get_raw(query.result)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_load_file
|
171
|
+
return unless Object.const_defined? :Mocha
|
172
|
+
File.expects(:read).
|
173
|
+
with("query_test.sql").
|
174
|
+
returns("select * from foo\n")
|
175
|
+
|
176
|
+
query = Ruport::Query.new "query_test.sql"
|
177
|
+
assert_equal "select * from foo", query.sql
|
26
178
|
end
|
27
179
|
|
28
|
-
def
|
180
|
+
def test_load_file_erb
|
181
|
+
return unless Object.const_defined? :Mocha
|
29
182
|
@table = 'bar'
|
30
|
-
|
31
|
-
|
183
|
+
File.expects(:read).
|
184
|
+
with("query_test.sql").
|
185
|
+
returns("select * from <%= @table %>\n")
|
186
|
+
|
187
|
+
query = Ruport::Query.new "query_test.sql", :binding => binding
|
188
|
+
assert_equal "select * from bar", query.sql
|
32
189
|
end
|
33
190
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
191
|
+
def test_load_file_not_found
|
192
|
+
return unless Object.const_defined? :Mocha
|
193
|
+
File.expects(:read).
|
194
|
+
with("query_test.sql").
|
195
|
+
raises(Errno::ENOENT)
|
196
|
+
Ruport.expects(:log).
|
197
|
+
with("Could not open query_test.sql",
|
198
|
+
:status => :fatal, :exception => LoadError).
|
199
|
+
raises(LoadError)
|
200
|
+
|
201
|
+
assert_raises LoadError do
|
202
|
+
query = Ruport::Query.new "query_test.sql"
|
42
203
|
end
|
43
|
-
assert_raise (LocalJumpError) { @query1.each }
|
44
204
|
end
|
45
205
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
assert_equal( "apple", @query1.instance_eval("@password") )
|
206
|
+
def test_each_cache_disabled
|
207
|
+
return unless Object.const_defined? :Mocha
|
208
|
+
query = @query[:uncached]
|
209
|
+
setup_mock_dbi(2)
|
51
210
|
|
52
|
-
|
211
|
+
result = []; query.each { |r| result << r.to_a }
|
212
|
+
assert_equal @data[0], result
|
213
|
+
|
214
|
+
result = []; query.each { |r| result << r.to_a }
|
215
|
+
assert_equal @data[1], result
|
216
|
+
end
|
53
217
|
|
54
|
-
|
55
|
-
|
56
|
-
|
218
|
+
def test_each_cache_enabled
|
219
|
+
return unless Object.const_defined? :Mocha
|
220
|
+
query = @query[:cached]
|
221
|
+
setup_mock_dbi(1)
|
57
222
|
|
58
|
-
|
223
|
+
result = []; query.each { |r| result << r.to_a }
|
224
|
+
assert_equal @data[0], result
|
225
|
+
|
226
|
+
result = []; query.each { |r| result << r.to_a }
|
227
|
+
assert_equal @data[0], result
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_each_multi
|
231
|
+
return unless Object.const_defined? :Mocha
|
232
|
+
query = @query[:multi]
|
233
|
+
setup_mock_dbi(2)
|
59
234
|
|
60
|
-
|
61
|
-
assert_equal
|
62
|
-
|
63
|
-
|
235
|
+
result = []; query.each { |r| result << r.to_a }
|
236
|
+
assert_equal @data[1], result
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_each_without_block
|
240
|
+
assert_raise (LocalJumpError) { @query[:precached].each }
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_select_source
|
244
|
+
query = @query[:precached]
|
245
|
+
assert_equal @sources[:default], get_query_source(query)
|
246
|
+
|
247
|
+
query.select_source :alternative
|
248
|
+
assert_equal @sources[:alternative], get_query_source(query)
|
249
|
+
|
250
|
+
query.select_source :default
|
251
|
+
assert_equal @sources[:default], get_query_source(query)
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_initialize_source_temporary
|
255
|
+
query = Ruport::Query.new "<unused>", @sources[:alternative]
|
256
|
+
assert_equal @sources[:alternative], get_query_source(query)
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_initialize_source_temporary_multiple
|
260
|
+
query1 = Ruport::Query.new "<unused>", @sources[:default]
|
261
|
+
query2 = Ruport::Query.new "<unused>", @sources[:alternative]
|
262
|
+
|
263
|
+
assert_equal @sources[:default], get_query_source(query1)
|
264
|
+
assert_equal @sources[:alternative], get_query_source(query2)
|
64
265
|
end
|
65
266
|
|
66
267
|
def test_generator
|
67
|
-
|
68
|
-
gen =
|
69
|
-
assert_equal [
|
70
|
-
assert_equal [
|
71
|
-
assert_equal [
|
268
|
+
query = @query[:precached]
|
269
|
+
gen = query.generator
|
270
|
+
assert_equal @data[0][0], gen.next
|
271
|
+
assert_equal @data[0][1], gen.next
|
272
|
+
assert_equal @data[0][2], gen.next
|
72
273
|
assert_raise(EOFError) { gen.next }
|
73
274
|
end
|
74
275
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
276
|
+
def test_to_table
|
277
|
+
return unless Object.const_defined? :Mocha
|
278
|
+
query = @query[:raw]
|
279
|
+
setup_mock_dbi(3, :returns => @data[0])
|
280
|
+
|
281
|
+
assert_equal @data[0], query.result
|
282
|
+
assert_equal @data[0].to_table(@columns), query.to_table
|
283
|
+
assert_equal @data[0], query.result
|
78
284
|
end
|
79
285
|
|
286
|
+
def test_to_csv
|
287
|
+
return unless Object.const_defined? :Mocha
|
288
|
+
query = @query[:plain]
|
289
|
+
setup_mock_dbi(1)
|
290
|
+
|
291
|
+
csv = @data[0].to_table(@columns).as(:csv)
|
292
|
+
assert_equal csv, query.to_csv
|
293
|
+
end
|
294
|
+
|
295
|
+
private
|
296
|
+
def setup_mock_dbi(count, options={})
|
297
|
+
sql = options[:sql] || @sql[0]
|
298
|
+
source = options[:source] || :default
|
299
|
+
returns = options[:returns] || Proc.new { @datasets.shift }
|
300
|
+
resultless = options[:resultless]
|
301
|
+
params = options[:params] || []
|
302
|
+
|
303
|
+
@dbh = mock("database_handle")
|
304
|
+
@sth = mock("statement_handle")
|
305
|
+
def @dbh.execute(*a, &b); execute__(*a, &b); ensure; sth__.finish if b; end
|
306
|
+
def @sth.each; data__.each { |x| yield(x) }; end
|
307
|
+
def @sth.fetch_all; data__; end
|
308
|
+
|
309
|
+
DBI.expects(:connect).
|
310
|
+
with(*@sources[source].values_at(:dsn, :user, :password)).
|
311
|
+
yields(@dbh).times(count)
|
312
|
+
@dbh.expects(:execute__).with(sql, *params).
|
313
|
+
yields(@sth).returns(@sth).times(count)
|
314
|
+
@dbh.stubs(:sth__).returns(@sth)
|
315
|
+
@sth.expects(:finish).with().times(count)
|
316
|
+
unless resultless
|
317
|
+
@sth.stubs(:fetchable?).returns(true)
|
318
|
+
@sth.stubs(:column_names).returns(@columns)
|
319
|
+
@sth.expects(:data__).returns(returns).times(count)
|
320
|
+
else
|
321
|
+
@sth.stubs(:fetchable?).returns(false)
|
322
|
+
@sth.stubs(:column_names).returns([])
|
323
|
+
@sth.stubs(:cancel)
|
324
|
+
@sth.expects(:data__).times(0)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def get_query_source(query)
|
329
|
+
[ :dsn, :user, :password ].inject({}) do |memo, var|
|
330
|
+
memo.update var => query.instance_variable_get("@#{var}")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def get_raw(table)
|
335
|
+
table.collect { |row| row.to_a }
|
336
|
+
end
|
80
337
|
end
|