qreport 0.0.10 → 0.1.0
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/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
|