qreport 0.0.10 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +11 -0
- data/lib/qreport/connection.rb +49 -134
- data/lib/qreport/connection/query.rb +138 -0
- data/lib/qreport/report_run.rb +3 -2
- data/lib/qreport/report_run/data.rb +33 -0
- data/lib/qreport/version.rb +1 -1
- data/spec/lib/qreport/connection_spec.rb +29 -10
- data/spec/lib/qreport/report_runner_spec.rb +1 -2
- metadata +6 -4
data/ChangeLog
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
2013-10-14 Kurt A. Stephens <ks.github@kurtstephens.com>
|
2
|
+
* v0.1.0: New Features.
|
3
|
+
* Handle Connection#close cleanly.
|
4
|
+
* Handle Rational data.
|
5
|
+
* Preliminary ARRAY[] data.
|
6
|
+
* Trap errors in ReportRun#data SELECT.
|
7
|
+
|
8
|
+
2013-10-02 Kurt A. Stephens <ks.github@kurtstephens.com>
|
9
|
+
* v0.0.11: New Features.
|
10
|
+
* ReportRun#data.columns: avoid pulling in entire report rows.
|
11
|
+
|
1
12
|
2013-10-01 Kurt A. Stephens <ks.github@kurtstephens.com>
|
2
13
|
* v0.0.10: New Features.
|
3
14
|
* Support CTE queries using "FROM (<subselect>) AS" syntax.
|
data/lib/qreport/connection.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'qreport'
|
2
2
|
require 'time' # iso8601
|
3
|
+
require 'rational' # Rational
|
3
4
|
require 'pp' # dump_result!
|
4
5
|
|
5
6
|
module Qreport
|
@@ -74,17 +75,23 @@ module Qreport
|
|
74
75
|
|
75
76
|
def close
|
76
77
|
raise Error, "close during transaction" if in_transaction?
|
78
|
+
_close
|
79
|
+
ensure
|
80
|
+
@invalid = false
|
81
|
+
end
|
82
|
+
|
83
|
+
def _close
|
77
84
|
if @conn
|
78
85
|
conn = @conn
|
79
86
|
@conn = nil
|
80
87
|
conn.close if @conn_owned
|
81
88
|
end
|
82
89
|
ensure
|
83
|
-
@invalid = false
|
84
|
-
@transaction_nesting = 0
|
85
90
|
@conn_owned = false
|
91
|
+
@transaction_nesting = 0
|
86
92
|
end
|
87
93
|
|
94
|
+
|
88
95
|
def in_transaction?; @transaction_nesting > 0; end
|
89
96
|
|
90
97
|
def transaction
|
@@ -181,7 +188,8 @@ module Qreport
|
|
181
188
|
conn.escape_identifier name.to_s
|
182
189
|
end
|
183
190
|
|
184
|
-
def escape_value val
|
191
|
+
def escape_value val, example_value = nil
|
192
|
+
example_val ||= val
|
185
193
|
case val
|
186
194
|
when SQL
|
187
195
|
val.to_s
|
@@ -191,16 +199,30 @@ module Qreport
|
|
191
199
|
T_
|
192
200
|
when false
|
193
201
|
F_
|
194
|
-
when
|
202
|
+
when Rational
|
203
|
+
val.to_f
|
204
|
+
when Numeric
|
195
205
|
val
|
196
206
|
when String, Symbol
|
197
207
|
"'" << conn.escape_string(val.to_s) << QUOTE
|
198
208
|
when Time
|
199
|
-
escape_value(val.iso8601(6)) <<
|
209
|
+
escape_value(val.iso8601(6)) << S_TIMESTAMP
|
200
210
|
when Range
|
201
211
|
"BETWEEN #{escape_value(val.first)} AND #{escape_value(val.last)}"
|
202
|
-
when Hash
|
212
|
+
when Hash
|
203
213
|
escape_value(val.to_json)
|
214
|
+
when Array
|
215
|
+
case
|
216
|
+
when true
|
217
|
+
# PUNT!!!
|
218
|
+
escape_value(val.to_json)
|
219
|
+
# DOES NOT HANDLE EMPTY ARRAY!!!
|
220
|
+
when example_val.all?{|x| Numeric === x || x.nil?} && ! example_val.empty?
|
221
|
+
"ARRAY[#{val.map{|x| escape_value(x, example_val[0])} * ','}]"
|
222
|
+
else
|
223
|
+
# PUNT!!!
|
224
|
+
escape_value(val.to_json)
|
225
|
+
end
|
204
226
|
else
|
205
227
|
raise TypeError, "cannot escape_value on #{val.class.name}"
|
206
228
|
end.to_s
|
@@ -210,6 +232,7 @@ module Qreport
|
|
210
232
|
T_ = "'t'::boolean".freeze
|
211
233
|
F_ = "'f'::boolean".freeze
|
212
234
|
T = 't'.freeze
|
235
|
+
S_TIMESTAMP = "::timestamp".freeze
|
213
236
|
|
214
237
|
def unescape_value val, type
|
215
238
|
case val
|
@@ -227,6 +250,15 @@ module Qreport
|
|
227
250
|
return func
|
228
251
|
end
|
229
252
|
case type
|
253
|
+
when /\[\]\Z/
|
254
|
+
et = $`
|
255
|
+
el = unescape_value_func(et)
|
256
|
+
lambda do | val, type |
|
257
|
+
# PP.pp([ val, type, et ])
|
258
|
+
val.gsub(/\A\{|\}\Z/, '').
|
259
|
+
split(',').
|
260
|
+
map{|x| x == 'NULL' ? nil : el.call(x, et)}
|
261
|
+
end
|
230
262
|
when /^bool/
|
231
263
|
lambda { | val, type | val == T }
|
232
264
|
when /^(int|smallint|bigint|oid|tid|xid|cid)/
|
@@ -286,145 +318,28 @@ module Qreport
|
|
286
318
|
end
|
287
319
|
|
288
320
|
def run_query! sql, query, options = nil
|
321
|
+
error = nil
|
289
322
|
options ||= EMPTY_Hash
|
323
|
+
# $stderr.puts " run_query! options = #{options.inspect}"
|
290
324
|
result = nil
|
291
325
|
begin
|
292
326
|
result = conn.async_exec(sql)
|
293
327
|
rescue ::PG::Error => exc
|
294
|
-
|
295
|
-
query.error = exc.inspect
|
296
|
-
raise exc unless options[:capture_error]
|
328
|
+
error = exc
|
297
329
|
rescue ::StandardError => exc
|
298
330
|
@invalid = true
|
299
|
-
|
300
|
-
raise exc unless options[:capture_error]
|
331
|
+
error = exc
|
301
332
|
end
|
302
333
|
result
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
attr_accessor :error, :cmd_status_raw, :cmd_status, :cmd_tuples
|
309
|
-
attr_accessor :nfields, :fields, :ftypes, :fmods
|
310
|
-
attr_accessor :type_names
|
311
|
-
attr_accessor :columns, :rows
|
312
|
-
|
313
|
-
def run!
|
314
|
-
@error = nil
|
315
|
-
sql = @sql_prepared = prepare_sql self.sql
|
316
|
-
if conn.verbose || options[:verbose]
|
317
|
-
out = conn.verbose_stream
|
318
|
-
out.puts "\n-- =================================================================== --"
|
319
|
-
out.puts sql
|
320
|
-
out.puts "-- ==== --"
|
321
|
-
end
|
322
|
-
return self if options[:dry_run]
|
323
|
-
if result = conn.run_query!(sql, self, options)
|
324
|
-
extract_results! result
|
325
|
-
end
|
326
|
-
self
|
327
|
-
end
|
328
|
-
|
329
|
-
def prepare_sql sql
|
330
|
-
sql = sql.sub(/[\s\n]*;[\s\n]*\Z/, '')
|
331
|
-
if options.key?(:limit)
|
332
|
-
sql = conn.with_limit sql, options[:limit]
|
333
|
-
end
|
334
|
-
if arguments = options[:arguments]
|
335
|
-
if values = arguments[:names_and_values]
|
336
|
-
n = conn.safe_sql(values.keys * ', ')
|
337
|
-
v = conn.safe_sql(values.keys.map{|k| ":#{k}"} * ', ')
|
338
|
-
sql = sql_replace_arguments(sql,
|
339
|
-
:NAMES => n,
|
340
|
-
:VALUES => v,
|
341
|
-
:NAMES_AND_VALUES => conn.safe_sql("( #{n} ) VALUES ( #{v} )"),
|
342
|
-
:SET_VALUES => conn.safe_sql(values.keys.map{|k| "#{conn.escape_identifier(k)} = :#{k}"} * ', '))
|
343
|
-
arguments = arguments.merge(values)
|
344
|
-
end
|
345
|
-
sql = sql_replace_arguments(sql, arguments)
|
346
|
-
end
|
347
|
-
sql
|
348
|
-
end
|
349
|
-
|
350
|
-
def sql_replace_arguments sql, arguments
|
351
|
-
sql = sql.gsub(/(:(\w+)\b([?]?))/) do | m |
|
352
|
-
name = $2.to_sym
|
353
|
-
optional = ! $3.empty?
|
354
|
-
if arguments.key?(name) || optional
|
355
|
-
val = arguments[name]
|
356
|
-
unless optional && val.nil?
|
357
|
-
val = conn.escape_value(val)
|
358
|
-
end
|
359
|
-
conn.verbose_stream.puts " #{name} => #{val}" if options[:verbose_arguments]
|
360
|
-
val
|
361
|
-
else
|
362
|
-
$1
|
363
|
-
end
|
364
|
-
end
|
365
|
-
sql = sql_replace_match sql
|
366
|
-
end
|
367
|
-
|
368
|
-
def sql_replace_match sql
|
369
|
-
sql = sql.gsub(/:~\s*\{\{([^\}]+?)\}\}\s*\{\{([^\}]+?)\}\}/) do | m |
|
370
|
-
expr = $1
|
371
|
-
val = $2
|
372
|
-
case expr
|
373
|
-
when /\A\s*BETWEEN\b/
|
374
|
-
"(#{val} #{expr})"
|
375
|
-
when "NULL"
|
376
|
-
"(#{val} IS NULL)"
|
377
|
-
else
|
378
|
-
"(#{val} = #{expr})"
|
379
|
-
end
|
380
|
-
end
|
381
|
-
sql
|
382
|
-
end
|
383
|
-
|
384
|
-
def extract_results! result
|
385
|
-
error = result.error_message
|
386
|
-
error &&= ! error.empty? && error
|
387
|
-
@error = error
|
388
|
-
@cmd_status_raw = result.cmd_status
|
389
|
-
@cmd_tuples = result.cmd_tuples
|
390
|
-
@nfields = result.nfields
|
391
|
-
@ntuples = result.ntuples
|
392
|
-
@fields = result.fields
|
393
|
-
@ftypes = (0 ... nfields).map{|i| result.ftype(i) }
|
394
|
-
@fmods = (0 ... nfields).map{|i| result.fmod(i) }
|
395
|
-
@rows = result.to_a
|
396
|
-
result.clear
|
397
|
-
self
|
398
|
-
end
|
399
|
-
|
400
|
-
def columns
|
401
|
-
@columns ||= @fields.zip(type_names)
|
402
|
-
end
|
403
|
-
|
404
|
-
def type_names
|
405
|
-
@type_names ||= (0 ... nfields).map{|i| conn.type_name(@ftypes[i], @fmods[i])}
|
406
|
-
end
|
407
|
-
|
408
|
-
def cmd_status
|
409
|
-
@cmd_status ||=
|
410
|
-
begin
|
411
|
-
x = @cmd_status_raw.split(/\s+/)
|
412
|
-
[ x[0] ] + x[1 .. -1].map(&:to_i)
|
413
|
-
end.freeze
|
414
|
-
end
|
415
|
-
|
416
|
-
def rows
|
417
|
-
return @rows if @rows_unescaped
|
418
|
-
@rows.each do | r |
|
419
|
-
columns.each do | c, t |
|
420
|
-
r[c] = conn.unescape_value(r[c], t)
|
421
|
-
end
|
422
|
-
end
|
423
|
-
@rows_unescaped = true
|
424
|
-
@rows
|
334
|
+
ensure
|
335
|
+
if error
|
336
|
+
# $stderr.puts " ERROR: #{exc.inspect}\n #{exc.backtrace * "\n "}"
|
337
|
+
query.error = error.inspect
|
338
|
+
raise error unless options[:capture_error]
|
425
339
|
end
|
426
|
-
|
427
340
|
end
|
341
|
+
|
428
342
|
end
|
429
343
|
end
|
430
344
|
|
345
|
+
require 'qreport/connection/query'
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'qreport/connection'
|
2
|
+
|
3
|
+
module Qreport
|
4
|
+
class Connection
|
5
|
+
class Query
|
6
|
+
attr_accessor :conn, :sql, :options
|
7
|
+
attr_accessor :sql_prepared
|
8
|
+
attr_accessor :error, :cmd_status_raw, :cmd_status, :cmd_tuples
|
9
|
+
attr_accessor :nfields, :fields, :ftypes, :fmods
|
10
|
+
attr_accessor :type_names
|
11
|
+
attr_accessor :columns, :rows
|
12
|
+
|
13
|
+
def run!
|
14
|
+
@error = nil
|
15
|
+
@fields = @ftypes = @mods = EMPTY_Array
|
16
|
+
@nfields = 0
|
17
|
+
sql = @sql_prepared = prepare_sql self.sql
|
18
|
+
if conn.verbose || options[:verbose]
|
19
|
+
out = conn.verbose_stream
|
20
|
+
out.puts "\n-- =================================================================== --"
|
21
|
+
out.puts sql
|
22
|
+
out.puts "-- ==== --"
|
23
|
+
end
|
24
|
+
return self if options[:dry_run]
|
25
|
+
if result = conn.run_query!(sql, self, options)
|
26
|
+
extract_results! result
|
27
|
+
end
|
28
|
+
self
|
29
|
+
ensure
|
30
|
+
@conn = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def prepare_sql sql
|
34
|
+
sql = sql.sub(/[\s\n]*;[\s\n]*\Z/, '')
|
35
|
+
if options.key?(:limit)
|
36
|
+
sql = conn.with_limit sql, options[:limit]
|
37
|
+
end
|
38
|
+
if arguments = options[:arguments]
|
39
|
+
if values = arguments[:names_and_values]
|
40
|
+
n = conn.safe_sql(values.keys * ', ')
|
41
|
+
v = conn.safe_sql(values.keys.map{|k| ":#{k}"} * ', ')
|
42
|
+
sql = sql_replace_arguments(sql,
|
43
|
+
:NAMES => n,
|
44
|
+
:VALUES => v,
|
45
|
+
:NAMES_AND_VALUES => conn.safe_sql("( #{n} ) VALUES ( #{v} )"),
|
46
|
+
:SET_VALUES => conn.safe_sql(values.keys.map{|k| "#{conn.escape_identifier(k)} = :#{k}"} * ', '))
|
47
|
+
arguments = arguments.merge(values)
|
48
|
+
end
|
49
|
+
sql = sql_replace_arguments(sql, arguments)
|
50
|
+
end
|
51
|
+
sql
|
52
|
+
end
|
53
|
+
|
54
|
+
def sql_replace_arguments sql, arguments
|
55
|
+
sql = sql.gsub(/(:(\w+)\b([?]?))/) do | m |
|
56
|
+
name = $2.to_sym
|
57
|
+
optional = ! $3.empty?
|
58
|
+
if arguments.key?(name) || optional
|
59
|
+
val = arguments[name]
|
60
|
+
unless optional && val.nil?
|
61
|
+
val = conn.escape_value(val)
|
62
|
+
end
|
63
|
+
conn.verbose_stream.puts " #{name} => #{val}" if options[:verbose_arguments]
|
64
|
+
val
|
65
|
+
else
|
66
|
+
$1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
sql = sql_replace_match sql
|
70
|
+
end
|
71
|
+
|
72
|
+
def sql_replace_match sql
|
73
|
+
sql = sql.gsub(/:~\s*\{\{([^\}]+?)\}\}\s*\{\{([^\}]+?)\}\}/) do | m |
|
74
|
+
expr = $1
|
75
|
+
val = $2
|
76
|
+
case expr
|
77
|
+
when /\A\s*BETWEEN\b/
|
78
|
+
"(#{val} #{expr})"
|
79
|
+
when "NULL"
|
80
|
+
"(#{val} IS NULL)"
|
81
|
+
else
|
82
|
+
"(#{val} = #{expr})"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
sql
|
86
|
+
end
|
87
|
+
|
88
|
+
def extract_results! result
|
89
|
+
error = result.error_message
|
90
|
+
error = nil if error.empty?
|
91
|
+
@error = error
|
92
|
+
@cmd_status_raw = result.cmd_status
|
93
|
+
@cmd_tuples = result.cmd_tuples
|
94
|
+
@nfields = result.nfields
|
95
|
+
@ntuples = result.ntuples
|
96
|
+
@fields = result.fields
|
97
|
+
@ftypes = (0 ... nfields).map{|i| result.ftype(i) }
|
98
|
+
@fmods = (0 ... nfields).map{|i| result.fmod(i) }
|
99
|
+
@rows = result.to_a
|
100
|
+
type_names
|
101
|
+
rows
|
102
|
+
self
|
103
|
+
ensure
|
104
|
+
result.clear
|
105
|
+
@conn = nil
|
106
|
+
end
|
107
|
+
|
108
|
+
def columns
|
109
|
+
@columns ||= @fields.zip(type_names)
|
110
|
+
end
|
111
|
+
|
112
|
+
def type_names
|
113
|
+
@type_names ||= (0 ... nfields).map{|i| @conn.type_name(@ftypes[i], @fmods[i])}
|
114
|
+
end
|
115
|
+
|
116
|
+
def cmd_status
|
117
|
+
@cmd_status ||=
|
118
|
+
begin
|
119
|
+
x = @cmd_status_raw.split(/\s+/)
|
120
|
+
[ x[0] ] + x[1 .. -1].map(&:to_i)
|
121
|
+
end.freeze
|
122
|
+
end
|
123
|
+
|
124
|
+
def rows
|
125
|
+
return @rows if @rows_unescaped
|
126
|
+
(@rows ||= [ ]).each do | r |
|
127
|
+
columns.each do | c, t |
|
128
|
+
r[c] = @conn.unescape_value(r[c], t)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
@rows_unescaped = true
|
132
|
+
@rows
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
data/lib/qreport/report_run.rb
CHANGED
@@ -182,8 +182,7 @@ END
|
|
182
182
|
|
183
183
|
# Return rows from this report run's report table.
|
184
184
|
def data
|
185
|
-
@data ||=
|
186
|
-
_select
|
185
|
+
@data ||= ReportRun::Data.new(self)
|
187
186
|
end
|
188
187
|
|
189
188
|
def select options = nil
|
@@ -229,3 +228,5 @@ END
|
|
229
228
|
end
|
230
229
|
end
|
231
230
|
end
|
231
|
+
|
232
|
+
require 'qreport/report_run/data'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'qreport/report_run'
|
2
|
+
|
3
|
+
module Qreport
|
4
|
+
class ReportRun
|
5
|
+
# Delays pulling in entire result set to determine columns of report result table.
|
6
|
+
class Data
|
7
|
+
attr_accessor :report_run
|
8
|
+
|
9
|
+
def initialize report_run; @report_run = report_run; end
|
10
|
+
|
11
|
+
def columns; _select0.columns; end
|
12
|
+
def type_names; _select0.type_names; end
|
13
|
+
def rows; _select.rows; end
|
14
|
+
def error; _select0.error; end
|
15
|
+
|
16
|
+
# Delegate all other methods to the Connection::Query object.
|
17
|
+
def method_missing sel, *args, &blk
|
18
|
+
_select.send(sel, *args, &blk)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def _select
|
24
|
+
@_select ||= report_run._select(:capture_error => true)
|
25
|
+
end
|
26
|
+
|
27
|
+
def _select0
|
28
|
+
@_select0 ||= (@_select || report_run._select(:capture_error => true, :limit => 0))
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/qreport/version.rb
CHANGED
@@ -2,18 +2,16 @@ require 'spec_helper'
|
|
2
2
|
require 'qreport/connection'
|
3
3
|
|
4
4
|
describe Qreport::Connection do
|
5
|
-
|
6
|
-
|
7
|
-
QREPORT_TEST_CONN[0] ||= Qreport::Connection.new
|
8
|
-
end
|
5
|
+
let(:conn) { Qreport::Connection.new }
|
6
|
+
after(:each) { conn._close }
|
9
7
|
|
10
8
|
it "can to connect to a test database." do
|
11
9
|
conn.conn.class.should == PG::Connection
|
12
10
|
end
|
13
11
|
|
14
12
|
it "can manage transaction state." do
|
15
|
-
conn.should_receive(:_transaction_begin).
|
16
|
-
conn.should_receive(:_transaction_commit).
|
13
|
+
conn.should_receive(:_transaction_begin).exactly(1).times
|
14
|
+
conn.should_receive(:_transaction_commit).exactly(1).times
|
17
15
|
conn.should_receive(:_transaction_abort).exactly(0).times
|
18
16
|
conn.in_transaction?.should == false
|
19
17
|
conn.transaction do
|
@@ -23,8 +21,8 @@ describe Qreport::Connection do
|
|
23
21
|
end
|
24
22
|
|
25
23
|
it "can manage nested transactions." do
|
26
|
-
conn.should_receive(:_transaction_begin).
|
27
|
-
conn.should_receive(:_transaction_commit).
|
24
|
+
conn.should_receive(:_transaction_begin).exactly(1).times
|
25
|
+
conn.should_receive(:_transaction_commit).exactly(1).times
|
28
26
|
conn.should_receive(:_transaction_abort).exactly(0).times
|
29
27
|
conn.in_transaction?.should == false
|
30
28
|
conn.transaction do
|
@@ -38,9 +36,9 @@ describe Qreport::Connection do
|
|
38
36
|
end
|
39
37
|
|
40
38
|
it "can manage transaction state during raised exceptions" do
|
41
|
-
conn.should_receive(:_transaction_begin).
|
39
|
+
conn.should_receive(:_transaction_begin).exactly(1).times
|
42
40
|
conn.should_receive(:_transaction_commit).exactly(0).times
|
43
|
-
conn.should_receive(:_transaction_abort).
|
41
|
+
conn.should_receive(:_transaction_abort).exactly(1).times
|
44
42
|
lambda do
|
45
43
|
conn.transaction do
|
46
44
|
raise Qreport::Error, "#{__LINE__}"
|
@@ -49,6 +47,19 @@ describe Qreport::Connection do
|
|
49
47
|
conn.in_transaction?.should == false
|
50
48
|
end
|
51
49
|
|
50
|
+
|
51
|
+
it "will error upon #close during transaction" do
|
52
|
+
conn.should_receive(:_transaction_begin).exactly(1).times
|
53
|
+
conn.should_receive(:_transaction_commit).exactly(0).times
|
54
|
+
conn.should_receive(:_transaction_abort).exactly(1).times
|
55
|
+
lambda do
|
56
|
+
conn.transaction do
|
57
|
+
conn.close
|
58
|
+
end
|
59
|
+
end.should raise_error(Qreport::Error)
|
60
|
+
conn.in_transaction?.should == false
|
61
|
+
end
|
62
|
+
|
52
63
|
it "can dup to create another connection." do
|
53
64
|
conn1 = Qreport::Connection.new
|
54
65
|
conn1.fd.should == nil
|
@@ -130,6 +141,14 @@ describe Qreport::Connection do
|
|
130
141
|
[ Time.parse('2011-04-27 13:23:00 -0500'), "'2011-04-27T13:23:00.000000-05:00'::timestamp", Time.parse('2011-04-27 13:23:00 -0500') ],
|
131
142
|
[ :IGNORE, "'13:23'::time", '13:23:00' ],
|
132
143
|
[ [ 1, "2", :three ], "'[1,\"2\",\"three\"]'", :IGNORE ],
|
144
|
+
=begin
|
145
|
+
DOES NOT WORK YET
|
146
|
+
[ [ 1, 2, 3 ], 'ARRAY[1,2,3]', ],
|
147
|
+
[ [ 1, 2, nil, 3 ], 'ARRAY[1,2,NULL,3]', ],
|
148
|
+
[ [ 1, 2.2, 3 ], 'ARRAY[1,2.2,3]', [ 1.0, 2.2, 3.0 ] ],
|
149
|
+
[ [ 1, nil, 2.2, 3 ], 'ARRAY[1,NULL,2.2,3]', [ 1.0, nil, 2.2, 3.0 ] ],
|
150
|
+
[ :IGNORE, 'ARRAY[1,NULL,2.2,3]', [ 1.0, nil, 2.2, 3.0 ] ],
|
151
|
+
=end
|
133
152
|
[ { :a => 1, "b" => 2 }, "'{\"a\":1,\"b\":2}'", :IGNORE ],
|
134
153
|
].each do | value, sql, return_value, sql_expr, sql_value |
|
135
154
|
if value != :IGNORE
|
@@ -56,6 +56,7 @@ describe Qreport::ReportRunner do
|
|
56
56
|
r2.data.columns.should == r.data.columns
|
57
57
|
r2.data.rows.should == r.data.rows
|
58
58
|
r2.data.rows.size.should == r.nrows
|
59
|
+
r2.data.cmd_status[0].should == "SELECT"
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
@@ -106,7 +107,6 @@ FROM articles
|
|
106
107
|
SELECT total_users.*, total_articles.*
|
107
108
|
FROM total_users, total_articles;
|
108
109
|
END
|
109
|
-
report_run.verbose = true
|
110
110
|
report_run.run! conn
|
111
111
|
report_run.columns.should == [["qr_run_id", "bigint"], ["qr_run_row", "bigint"], ["total_users", "bigint"], ["total_articles", "bigint"]]
|
112
112
|
rows = report_run.select.rows
|
@@ -165,7 +165,6 @@ END
|
|
165
165
|
|
166
166
|
[ '1 days', '2 days', '30 days', '60 days' ].each do | interval |
|
167
167
|
report_run = Qreport::ReportRun.new(:name => :users_with_articles, :description => interval, :variant => interval)
|
168
|
-
report_run.verbose = verbose
|
169
168
|
report_run.arguments = {
|
170
169
|
:now => now,
|
171
170
|
:interval => interval,
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qreport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -140,10 +140,12 @@ files:
|
|
140
140
|
- Rakefile
|
141
141
|
- lib/qreport.rb
|
142
142
|
- lib/qreport/connection.rb
|
143
|
+
- lib/qreport/connection/query.rb
|
143
144
|
- lib/qreport/initialization.rb
|
144
145
|
- lib/qreport/main.rb
|
145
146
|
- lib/qreport/model.rb
|
146
147
|
- lib/qreport/report_run.rb
|
148
|
+
- lib/qreport/report_run/data.rb
|
147
149
|
- lib/qreport/report_runner.rb
|
148
150
|
- lib/qreport/version.rb
|
149
151
|
- qreport.gemspec
|
@@ -164,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
166
|
version: '0'
|
165
167
|
segments:
|
166
168
|
- 0
|
167
|
-
hash:
|
169
|
+
hash: 2467578902340912211
|
168
170
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
171
|
none: false
|
170
172
|
requirements:
|
@@ -173,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
175
|
version: '0'
|
174
176
|
segments:
|
175
177
|
- 0
|
176
|
-
hash:
|
178
|
+
hash: 2467578902340912211
|
177
179
|
requirements: []
|
178
180
|
rubyforge_project:
|
179
181
|
rubygems_version: 1.8.25
|