jzimmek-reportme 0.2.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/reportme.rb +28 -2
- data/lib/reportme/report.rb +18 -3
- data/lib/reportme/report_factory.rb +201 -83
- data/test/reportme_test.rb +196 -59
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/reportme.rb
CHANGED
@@ -2,5 +2,31 @@ require 'rubygems'
|
|
2
2
|
require 'activerecord'
|
3
3
|
require "actionmailer"
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
class Object
|
6
|
+
|
7
|
+
def self.dsl_attr(name, opts={})
|
8
|
+
|
9
|
+
self.class.send(:define_method, name) do |value|
|
10
|
+
key = "@@#{name}".to_sym
|
11
|
+
class_variable_set(key, value)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
self.class.send(:define_method, "#{name}_value".to_sym) do
|
16
|
+
class_variable_get("@@#{name}".to_sym)
|
17
|
+
end
|
18
|
+
|
19
|
+
self.class.send(:define_method, "#{name}_reset".to_sym) do
|
20
|
+
default = opts[:default].try(:call)
|
21
|
+
class_variable_set("@@#{name}".to_sym, default)
|
22
|
+
end
|
23
|
+
|
24
|
+
default = opts[:default].try(:call)
|
25
|
+
send(name, default)
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'reportme/report_factory'
|
32
|
+
|
data/lib/reportme/report.rb
CHANGED
@@ -2,17 +2,31 @@ module Reportme
|
|
2
2
|
class Report
|
3
3
|
|
4
4
|
attr_reader :name
|
5
|
-
|
6
|
-
def initialize(report_factory, name)
|
5
|
+
|
6
|
+
def initialize(report_factory, name, temporary=false)
|
7
7
|
@report_factory = report_factory
|
8
8
|
@name = name
|
9
9
|
@periods = [:today, :day, :week, :calendar_week, :month, :calendar_month]
|
10
|
+
@depends_on = []
|
11
|
+
@temporary = temporary
|
10
12
|
end
|
11
13
|
|
14
|
+
def temporary?
|
15
|
+
@temporary
|
16
|
+
end
|
17
|
+
|
12
18
|
def source(&block)
|
13
19
|
@source = block
|
14
20
|
end
|
15
21
|
|
22
|
+
def depends_on(dependencies=[])
|
23
|
+
@depends_on += dependencies
|
24
|
+
end
|
25
|
+
|
26
|
+
def dependencies
|
27
|
+
@depends_on
|
28
|
+
end
|
29
|
+
|
16
30
|
def periods(wanted_periods=[])
|
17
31
|
unless wanted_periods.blank?
|
18
32
|
@periods.clear
|
@@ -31,7 +45,8 @@ module Reportme
|
|
31
45
|
end
|
32
46
|
|
33
47
|
def table_name(period)
|
34
|
-
"
|
48
|
+
prefix = temporary? ? "tmp_" : ""
|
49
|
+
"#{prefix}#{name}_#{period}"
|
35
50
|
end
|
36
51
|
|
37
52
|
def table_exist?(period)
|
@@ -3,51 +3,42 @@ require 'reportme/mailer'
|
|
3
3
|
|
4
4
|
module Reportme
|
5
5
|
class ReportFactory
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
6
|
+
|
7
|
+
dsl_attr :reports, :default => lambda{ [] }
|
8
|
+
dsl_attr :subscribtions, :default => lambda{ {} }
|
9
|
+
dsl_attr :properties, :default => lambda{ {} }
|
10
|
+
dsl_attr :init
|
12
11
|
|
13
12
|
def initialize
|
14
|
-
@reports = []
|
15
|
-
@subscribtions = {}
|
16
13
|
@report_exists_cache = []
|
17
14
|
end
|
18
15
|
|
19
|
-
def connection(properties)
|
20
|
-
|
21
|
-
ActiveRecord::Base.establish_connection(@properties)
|
16
|
+
def self.connection(properties)
|
17
|
+
ActiveRecord::Base.establish_connection(@@properties = properties)
|
22
18
|
end
|
23
19
|
|
24
|
-
def smtp(settings)
|
20
|
+
def self.smtp(settings)
|
25
21
|
ActionMailer::Base.smtp_settings = settings
|
26
22
|
end
|
27
23
|
|
28
|
-
def mail(from, recipients, subject, body, attachments=[])
|
24
|
+
def self.mail(from, recipients, subject, body, attachments=[])
|
29
25
|
Mailer.deliver_message(from, recipients, subject, body, attachments)
|
30
26
|
end
|
31
27
|
|
32
|
-
def
|
33
|
-
raise "
|
34
|
-
|
35
|
-
|
36
|
-
@since = since.to_date
|
37
|
-
end
|
38
|
-
|
39
|
-
def init(&block)
|
40
|
-
raise "only one init block allowed" if @init
|
41
|
-
@init = block;
|
28
|
+
def self.init(&block)
|
29
|
+
raise "only one init block allowed" if @@init
|
30
|
+
@@init = block;
|
42
31
|
end
|
43
32
|
|
44
33
|
def self.periods(today)
|
45
34
|
|
35
|
+
today = today.to_date
|
36
|
+
|
46
37
|
r = []
|
47
38
|
p = []
|
48
39
|
|
49
40
|
# period "today" will never be generated for previous days
|
50
|
-
p << :today if today
|
41
|
+
p << :today if today == Date.today
|
51
42
|
p += [:day, :week, :calendar_week, :month, :calendar_month]
|
52
43
|
|
53
44
|
p.each do |period|
|
@@ -100,13 +91,17 @@ module Reportme
|
|
100
91
|
exists
|
101
92
|
end
|
102
93
|
|
103
|
-
def schema_name
|
104
|
-
schema =
|
94
|
+
def self.schema_name
|
95
|
+
schema = @@properties[:database]
|
105
96
|
raise "missing :database in connection properties" unless schema
|
106
97
|
schema
|
107
98
|
end
|
108
|
-
|
99
|
+
|
109
100
|
def columns(table_name)
|
101
|
+
self.class.columns(table_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.columns(table_name)
|
110
105
|
sql = <<-SQL
|
111
106
|
select
|
112
107
|
column_name
|
@@ -120,23 +115,17 @@ module Reportme
|
|
120
115
|
select_values(sql)
|
121
116
|
end
|
122
117
|
|
123
|
-
def
|
124
|
-
@report_exists_cache.clear
|
125
|
-
exec("drop table if exists #{report_information_table_name};")
|
118
|
+
def ensure_report_tables_exist(report)
|
126
119
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
def ensure_report_table_exist(report, period)
|
135
|
-
unless report.table_exist?(period)
|
136
|
-
table_name = report.table_name(period)
|
137
|
-
sql = report.sql('0000-00-00 00:00:00', '0000-00-00 00:00:00', period)
|
120
|
+
[:today, :day, :week, :calendar_week, :month, :calendar_month].each do |period|
|
121
|
+
next unless report.wants_period?(period)
|
122
|
+
|
123
|
+
unless report.table_exist?(period)
|
124
|
+
table_name = report.table_name(period)
|
125
|
+
sql = report.sql('0000-00-00 00:00:00', '0000-00-00 00:00:00', period)
|
138
126
|
|
139
|
-
|
127
|
+
exec("create table #{table_name} ENGINE=InnoDB default CHARSET=utf8 as #{sql} limit 0;")
|
128
|
+
end
|
140
129
|
end
|
141
130
|
end
|
142
131
|
|
@@ -186,46 +175,152 @@ module Reportme
|
|
186
175
|
exec("insert into #{report_information_table_name} values ('#{table_name}', '#{von}', '#{bis}', now());")
|
187
176
|
exec("insert into #{table_name} select #{column_names.join(',')} from #{report.table_name(:day)} as d where d.von between '#{von}' and '#{(_von + num_days.days).strftime("%Y-%m-%d 00:00:00")}';")
|
188
177
|
|
189
|
-
notify_subscriber(report.name, period_name, _von)
|
178
|
+
self.class.notify_subscriber(report.name, period_name, _von)
|
190
179
|
end
|
191
180
|
end
|
192
181
|
end
|
193
182
|
|
194
|
-
def
|
195
|
-
|
196
|
-
|
197
|
-
|
183
|
+
def validate_dependencies
|
184
|
+
@@reports.each do |r|
|
185
|
+
r.dependencies.each do |d|
|
186
|
+
raise "report #{r.name} depends on non existing report #{d}" unless self.class.has_report?(d)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
198
190
|
|
199
|
-
|
200
|
-
|
191
|
+
def __fill_periods_queue(since)
|
201
192
|
periods_queue = []
|
202
193
|
|
203
|
-
|
204
|
-
ReportFactory.periods(
|
194
|
+
loop do
|
195
|
+
ReportFactory.periods(since).each do |period|
|
205
196
|
periods_queue << period
|
206
197
|
end
|
207
|
-
|
198
|
+
since += 1.day
|
199
|
+
break if since.future?
|
200
|
+
end
|
201
|
+
|
202
|
+
periods_queue
|
203
|
+
end
|
204
|
+
|
205
|
+
def run(since=Date.today)
|
206
|
+
|
207
|
+
raise "since cannot be in the future" if since.future?
|
208
|
+
|
209
|
+
begin
|
210
|
+
@@init.call if @@init
|
211
|
+
|
212
|
+
ensure_report_informations_table_exist
|
213
|
+
|
214
|
+
validate_dependencies
|
215
|
+
|
216
|
+
run_dependency_aware(@@reports) do |report|
|
217
|
+
ensure_report_tables_exist(report)
|
218
|
+
end
|
219
|
+
|
220
|
+
periods_queue = __fill_periods_queue(since)
|
221
|
+
|
222
|
+
# we will generate all daily reports first.
|
223
|
+
# this will speed up generation of weekly and monthly reports.
|
224
|
+
|
225
|
+
self.class.__sort_periods(periods_queue).each do |period|
|
226
|
+
|
227
|
+
run_dependency_aware(@@reports) do |report|
|
228
|
+
__report_period(report, period)
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
ensure
|
233
|
+
@@reports.each do |report|
|
234
|
+
|
235
|
+
if report.temporary?
|
236
|
+
[:today, :day, :week, :calendar_week, :month, :calendar_month].each do |period|
|
237
|
+
|
238
|
+
table_name = report.table_name(period)
|
239
|
+
|
240
|
+
exec("delete from #{report_information_table_name} where report = '#{table_name}';")
|
241
|
+
exec("drop table if exists #{table_name};")
|
242
|
+
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
208
247
|
end
|
209
248
|
|
210
|
-
|
211
|
-
|
249
|
+
end
|
250
|
+
|
251
|
+
def run_dependency_aware(reports, &block)
|
252
|
+
|
253
|
+
dependencies = __dependency_hash
|
254
|
+
reports = reports.dup
|
212
255
|
|
213
|
-
|
214
|
-
|
256
|
+
while true
|
257
|
+
|
258
|
+
break if reports.blank?
|
259
|
+
|
260
|
+
num_run = 0
|
261
|
+
|
262
|
+
reports.each do |r|
|
263
|
+
|
264
|
+
unless dependencies[r.name].blank?
|
265
|
+
puts "report ['#{r.name}'] waits on dependencies: #{dependencies[r.name].collect{|d|d.name}.join(',')}"
|
266
|
+
next
|
267
|
+
end
|
268
|
+
|
269
|
+
block.call(r)
|
270
|
+
|
271
|
+
dependencies.each_pair do |key, values|
|
272
|
+
|
273
|
+
if values.include?(r)
|
274
|
+
# puts "remove '#{r[:name]}' from '#{key}' list of dependencies"
|
275
|
+
values.delete(r)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
num_run += 1
|
280
|
+
reports.delete(r)
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
raise "deadlock" if num_run == 0
|
285
|
+
|
215
286
|
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.__sort_periods(periods)
|
291
|
+
|
292
|
+
sorting = {
|
293
|
+
:today => 99,
|
294
|
+
:day => 1,
|
295
|
+
:week => 2,
|
296
|
+
:calendar_week => 3,
|
297
|
+
:month => 4,
|
298
|
+
:calendar_month => 5
|
299
|
+
}
|
300
|
+
|
301
|
+
periods.sort{|a, b| sorting[a[:name]] <=> sorting[b[:name]]}
|
302
|
+
|
303
|
+
end
|
216
304
|
|
217
|
-
|
218
|
-
|
305
|
+
def __dependency_hash
|
306
|
+
dependencies = {}
|
307
|
+
@@reports.each do |r|
|
308
|
+
|
309
|
+
dependencies[r.name] = []
|
310
|
+
|
311
|
+
r.dependencies.each do |d|
|
312
|
+
dependencies[r.name] << self.class.report_by_name(d)
|
313
|
+
end
|
219
314
|
end
|
220
315
|
|
316
|
+
dependencies
|
221
317
|
end
|
222
318
|
|
223
|
-
def
|
224
|
-
@reports.each do |r|
|
319
|
+
def __report_period(r, period)
|
225
320
|
|
226
|
-
|
321
|
+
period_name = period[:name]
|
227
322
|
|
228
|
-
|
323
|
+
if r.wants_period?(period_name)
|
229
324
|
|
230
325
|
_von = period[:von]
|
231
326
|
_bis = period[:bis]
|
@@ -239,8 +334,6 @@ module Reportme
|
|
239
334
|
sql = r.sql(von, bis, period_name)
|
240
335
|
|
241
336
|
puts "report: #{r.table_name(period_name)} von: #{von}, bis: #{bis}"
|
242
|
-
|
243
|
-
ensure_report_table_exist(r, period_name)
|
244
337
|
|
245
338
|
report_exists = report_exists?(table_name, von, bis)
|
246
339
|
|
@@ -257,30 +350,35 @@ module Reportme
|
|
257
350
|
if !report_exists || period_name == :today
|
258
351
|
ActiveRecord::Base.transaction do
|
259
352
|
exec("insert into #{report_information_table_name} values ('#{table_name}', '#{von}', '#{bis}', now());") unless report_exists
|
260
|
-
|
261
|
-
if period_name == :today
|
262
|
-
exec("truncate #{table_name};")
|
263
|
-
end
|
353
|
+
|
354
|
+
exec("truncate #{table_name};") if period_name == :today
|
264
355
|
|
265
356
|
exec("insert into #{table_name} #{sql};")
|
266
357
|
|
267
|
-
notify_subscriber(r.name, period_name, _von)
|
358
|
+
self.class.notify_subscriber(r.name, period_name, _von)
|
268
359
|
end
|
269
360
|
end
|
270
361
|
|
271
|
-
|
272
362
|
end
|
273
363
|
|
274
364
|
end
|
275
|
-
|
365
|
+
|
276
366
|
def exec(sql)
|
367
|
+
self.class.exec(sql)
|
368
|
+
end
|
369
|
+
|
370
|
+
def self.exec(sql)
|
277
371
|
puts "// ------------------------"
|
278
372
|
puts "exec: #{sql}"
|
279
373
|
puts "------------------------ //"
|
280
374
|
ActiveRecord::Base.connection.execute(sql)
|
281
375
|
end
|
282
|
-
|
376
|
+
|
283
377
|
def select_value(sql)
|
378
|
+
self.class.select_value(sql)
|
379
|
+
end
|
380
|
+
|
381
|
+
def self.select_value(sql)
|
284
382
|
puts "// ------------------------"
|
285
383
|
puts "select_value: #{sql}"
|
286
384
|
puts "------------------------ //"
|
@@ -288,6 +386,10 @@ module Reportme
|
|
288
386
|
end
|
289
387
|
|
290
388
|
def select_one(sql)
|
389
|
+
self.class.select_one(sql)
|
390
|
+
end
|
391
|
+
|
392
|
+
def self.select_one(sql)
|
291
393
|
puts "// ------------------------"
|
292
394
|
puts "select_one: #{sql}"
|
293
395
|
puts "------------------------ //"
|
@@ -295,6 +397,10 @@ module Reportme
|
|
295
397
|
end
|
296
398
|
|
297
399
|
def select_all(sql)
|
400
|
+
self.class.select_all(sql)
|
401
|
+
end
|
402
|
+
|
403
|
+
def self.select_all(sql)
|
298
404
|
puts "// ------------------------"
|
299
405
|
puts "select_all: #{sql}"
|
300
406
|
puts "------------------------ //"
|
@@ -302,6 +408,10 @@ module Reportme
|
|
302
408
|
end
|
303
409
|
|
304
410
|
def select_rows(sql)
|
411
|
+
self.class.select_rows(sql)
|
412
|
+
end
|
413
|
+
|
414
|
+
def self.select_rows(sql)
|
305
415
|
puts "// ------------------------"
|
306
416
|
puts "select_rows: #{sql}"
|
307
417
|
puts "------------------------ //"
|
@@ -309,32 +419,40 @@ module Reportme
|
|
309
419
|
end
|
310
420
|
|
311
421
|
def select_values(sql)
|
422
|
+
self.class.select_values(sql)
|
423
|
+
end
|
424
|
+
|
425
|
+
def self.select_values(sql)
|
312
426
|
puts "// ------------------------"
|
313
427
|
puts "select_values: #{sql}"
|
314
428
|
puts "------------------------ //"
|
315
429
|
ActiveRecord::Base.connection.select_values(sql)
|
316
430
|
end
|
317
431
|
|
318
|
-
def has_subscribtion?(report_name)
|
319
|
-
|
432
|
+
def self.has_subscribtion?(report_name)
|
433
|
+
!@@subscribtions[report_name].blank?
|
434
|
+
end
|
435
|
+
|
436
|
+
def self.report_by_name(report_name)
|
437
|
+
@@reports.find{|r|r.name == report_name}
|
320
438
|
end
|
321
439
|
|
322
|
-
def has_report?(report_name)
|
323
|
-
|
440
|
+
def self.has_report?(report_name)
|
441
|
+
!@@reports.find{|r|r.name == report_name}.blank?
|
324
442
|
end
|
325
443
|
|
326
|
-
def subscribe(report_name, &block)
|
444
|
+
def self.subscribe(report_name, &block)
|
327
445
|
report_name = report_name.to_sym
|
328
446
|
|
329
447
|
raise "report: #{report_name} does not exist" unless has_report?(report_name)
|
330
448
|
|
331
|
-
existing =
|
449
|
+
existing = @@subscribtions[report_name] || (@@subscribtions[report_name] = [])
|
332
450
|
existing << block
|
333
451
|
end
|
334
452
|
|
335
|
-
def notify_subscriber(report_name, period, von)
|
453
|
+
def self.notify_subscriber(report_name, period, von)
|
336
454
|
|
337
|
-
(
|
455
|
+
(@@subscribtions[report_name] || []).each do |subscription|
|
338
456
|
begin
|
339
457
|
subscription.call(period, von)
|
340
458
|
rescue Exception => e
|
@@ -344,14 +462,14 @@ module Reportme
|
|
344
462
|
|
345
463
|
end
|
346
464
|
|
347
|
-
def report(name, &block)
|
465
|
+
def self.report(name, temporary=false, &block)
|
348
466
|
|
349
467
|
name = name.to_sym
|
350
468
|
|
351
|
-
r = Report.new(self, name)
|
469
|
+
r = Report.new(self, name, temporary)
|
352
470
|
r.instance_eval(&block)
|
353
471
|
|
354
|
-
|
472
|
+
@@reports << r
|
355
473
|
end
|
356
474
|
|
357
475
|
end
|
data/test/reportme_test.rb
CHANGED
@@ -16,55 +16,73 @@ class ReportmeTest < Test::Unit::TestCase
|
|
16
16
|
)
|
17
17
|
SQL
|
18
18
|
end
|
19
|
+
|
20
|
+
class TestReport < Reportme::ReportFactory
|
21
|
+
end
|
19
22
|
|
20
23
|
def create_visit_report_factory(opts={})
|
21
24
|
|
22
25
|
defaults = {
|
23
26
|
:periods => [],
|
24
|
-
:
|
27
|
+
:init => lambda {}
|
25
28
|
}
|
26
29
|
|
27
30
|
opts = defaults.merge(opts)
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
SQL
|
51
|
-
end
|
32
|
+
TestReport.connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
33
|
+
TestReport.init do
|
34
|
+
opts[:init].call
|
35
|
+
end
|
36
|
+
TestReport.report :visits do
|
37
|
+
periods opts[:periods]
|
38
|
+
source do |von, bis|
|
39
|
+
<<-SQL
|
40
|
+
select
|
41
|
+
'#{von}' as von,
|
42
|
+
date(created_at) as datum,
|
43
|
+
channel,
|
44
|
+
count(1) as cnt
|
45
|
+
from
|
46
|
+
visits
|
47
|
+
where
|
48
|
+
created_at between '#{von}' and '#{bis}'
|
49
|
+
group by
|
50
|
+
date(created_at),
|
51
|
+
channel
|
52
|
+
SQL
|
52
53
|
end
|
53
54
|
end
|
54
|
-
|
55
|
+
|
56
|
+
@rme = TestReport.new
|
57
|
+
|
55
58
|
end
|
56
59
|
|
57
60
|
def exec(sql)
|
61
|
+
puts "exec: #{sql}"
|
58
62
|
ActiveRecord::Base.connection.execute(sql)
|
59
63
|
end
|
60
64
|
|
61
65
|
def one(sql)
|
66
|
+
puts "one: #{sql}"
|
62
67
|
ActiveRecord::Base.connection.select_one(sql)
|
63
68
|
end
|
64
69
|
|
65
70
|
def teardown
|
66
71
|
unless @debug
|
67
|
-
|
72
|
+
exec("drop table if exists report_informations;")
|
73
|
+
|
74
|
+
[:today, :day, :week, :calendar_week, :month, :calendar_month].each do |period|
|
75
|
+
|
76
|
+
TestReport.reports_value.each do |report|
|
77
|
+
exec("drop table if exists #{report.table_name(period)};")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
TestReport.reports_reset
|
82
|
+
TestReport.init_reset
|
83
|
+
TestReport.subscribtions_reset
|
84
|
+
TestReport.properties_reset
|
85
|
+
|
68
86
|
exec("truncate visits;");
|
69
87
|
end
|
70
88
|
end
|
@@ -82,6 +100,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
82
100
|
assert_equal 2, one("select cnt from visits_today where channel = 'sem' and datum = curdate()")["cnt"].to_i
|
83
101
|
end
|
84
102
|
|
103
|
+
|
85
104
|
should "create visitors in the today report for channel sem and seo" do
|
86
105
|
exec("insert into visits values (null, 'sem', now())");
|
87
106
|
exec("insert into visits values (null, 'sem', now())");
|
@@ -126,6 +145,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
126
145
|
|
127
146
|
should "create a daily report for the previous 3 days" do
|
128
147
|
|
148
|
+
|
129
149
|
#should be ignored
|
130
150
|
exec("insert into visits values (null, 'sem', curdate());");
|
131
151
|
|
@@ -137,7 +157,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
137
157
|
# should be ignored
|
138
158
|
exec("insert into visits values (null, 'sem', date_sub(curdate(), interval 5 day));");
|
139
159
|
|
140
|
-
create_visit_report_factory(:
|
160
|
+
create_visit_report_factory(:periods => [:day]).run(3.days.ago)
|
141
161
|
assert_equal 4, one("select count(1) as cnt from visits_day where von between date_sub(curdate(), interval 4 day) and date_sub(curdate(), interval 1 day)")["cnt"].to_i
|
142
162
|
end
|
143
163
|
|
@@ -159,10 +179,12 @@ class ReportmeTest < Test::Unit::TestCase
|
|
159
179
|
# should be ignored in weekly
|
160
180
|
exec("insert into visits values (null, 'sem', date_sub(curdate(), interval 9 day));");
|
161
181
|
|
162
|
-
create_visit_report_factory(:
|
182
|
+
create_visit_report_factory(:periods => [:day]).run(10.days.ago)
|
163
183
|
|
164
184
|
exec("truncate visits;")
|
165
185
|
|
186
|
+
Reportme::ReportFactory.init_reset
|
187
|
+
|
166
188
|
create_visit_report_factory(:periods => [:week]).run
|
167
189
|
|
168
190
|
assert_equal 7, one("select count(1) as cnt from visits_week where date(von) between date_sub(curdate(), interval 7 day) and date_sub(curdate(), interval 1 day)")["cnt"].to_i
|
@@ -320,7 +342,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
320
342
|
|
321
343
|
assert_equal '2009-04-01 00:00:00'.to_datetime, periods[:calendar_month][:von]
|
322
344
|
assert_equal '2009-04-30 23:59:59'.to_datetime, periods[:calendar_month][:bis]
|
323
|
-
|
345
|
+
|
324
346
|
##
|
325
347
|
# today
|
326
348
|
##
|
@@ -333,7 +355,7 @@ class ReportmeTest < Test::Unit::TestCase
|
|
333
355
|
assert_equal "#{today.strftime('%Y-%m-%d')} 23:59:59".to_datetime, periods[:today][:bis]
|
334
356
|
|
335
357
|
end
|
336
|
-
|
358
|
+
|
337
359
|
should "create the calendar_weekly report by using 7 daily reports" do
|
338
360
|
|
339
361
|
today = '2009-06-24'
|
@@ -353,58 +375,84 @@ class ReportmeTest < Test::Unit::TestCase
|
|
353
375
|
exec("insert into visits values (null, 'sem', date_sub('#{today}', interval 9 day));");
|
354
376
|
# should be ignored in weekly
|
355
377
|
exec("insert into visits values (null, 'sem', date_sub('#{today}', interval 10 day));");
|
378
|
+
|
379
|
+
create_visit_report_factory(:periods => [:day]).run(15.days.ago)
|
380
|
+
|
381
|
+
exec("truncate visits;")
|
382
|
+
|
383
|
+
Reportme::ReportFactory.init_reset
|
356
384
|
|
357
|
-
|
385
|
+
d1 = Date.today
|
386
|
+
d2 = today.to_date
|
387
|
+
|
388
|
+
num_days = 0
|
358
389
|
|
359
|
-
|
390
|
+
while d2.past?
|
391
|
+
d2 += 1.day
|
392
|
+
num_days += 1
|
393
|
+
end
|
394
|
+
|
395
|
+
create_visit_report_factory(:periods => [:calendar_week]).run(num_days.days.ago)
|
360
396
|
|
361
|
-
|
397
|
+
day_lastweek = today.to_date - 7.days
|
398
|
+
|
399
|
+
monday = day_lastweek - (day_lastweek.cwday - 1).days
|
400
|
+
|
401
|
+
von, bis = [monday, monday + 6.days]
|
402
|
+
|
403
|
+
von = von.to_datetime
|
404
|
+
bis = bis.to_datetime + 23.hours + 59.minutes + 59.seconds
|
362
405
|
|
363
|
-
|
406
|
+
sql = "select count(1) as cnt from visits_calendar_week where von between '#{von.strftime('%Y-%m-%d 00:00:00')}' and '#{bis.strftime('%Y-%m-%d 23:59:59')}'"
|
407
|
+
|
408
|
+
# assert_equal 7, one("select count(1) as cnt from visits_calendar_week where von between '2009-06-15 00:00:00' and '2009-06-21 00:00:00'")["cnt"].to_i
|
409
|
+
assert_equal 7, one(sql)["cnt"].to_i
|
364
410
|
|
365
411
|
end
|
366
|
-
|
412
|
+
|
367
413
|
should "probe existing reports" do
|
368
414
|
rme = create_visit_report_factory
|
369
|
-
assert rme.has_report?(:visits)
|
370
|
-
assert !rme.has_report?(:some_not_existing_report)
|
415
|
+
assert rme.class.has_report?(:visits)
|
416
|
+
assert !rme.class.has_report?(:some_not_existing_report)
|
371
417
|
end
|
372
|
-
|
418
|
+
|
373
419
|
should "subscribe to visits report" do
|
374
420
|
rme = create_visit_report_factory
|
375
|
-
rme.subscribe :visits do
|
421
|
+
rme.class.subscribe :visits do
|
376
422
|
end
|
377
|
-
assert rme.has_subscribtion?(:visits)
|
423
|
+
assert rme.class.has_subscribtion?(:visits)
|
378
424
|
end
|
379
425
|
|
380
426
|
should "fail on subscribtion to not existing report" do
|
381
427
|
rme = create_visit_report_factory
|
382
428
|
assert_raise RuntimeError do
|
383
|
-
rme.subscribe :some_not_existing_report do
|
429
|
+
rme.class.subscribe :some_not_existing_report do
|
384
430
|
end
|
385
431
|
end
|
386
432
|
end
|
387
433
|
|
388
434
|
should "notify subscriptions" do
|
389
435
|
notifed = false
|
390
|
-
|
436
|
+
|
391
437
|
rme = create_visit_report_factory
|
392
|
-
rme.subscribe :visits do
|
438
|
+
rme.class.subscribe :visits do
|
393
439
|
notifed = true
|
394
440
|
end
|
395
441
|
|
396
|
-
rme.notify_subscriber(:visits, :day, '2009-01-01'.to_datetime)
|
442
|
+
rme.class.notify_subscriber(:visits, :day, '2009-01-01'.to_datetime)
|
397
443
|
|
398
444
|
assert notifed
|
399
445
|
end
|
400
446
|
|
401
447
|
should "call initializer before running reports" do
|
402
448
|
initialized = false
|
403
|
-
|
404
|
-
rme = create_visit_report_factory
|
405
|
-
|
406
|
-
|
407
|
-
|
449
|
+
|
450
|
+
rme = create_visit_report_factory({
|
451
|
+
:init => lambda {
|
452
|
+
initialized = true
|
453
|
+
}
|
454
|
+
})
|
455
|
+
|
408
456
|
rme.run
|
409
457
|
|
410
458
|
assert initialized
|
@@ -412,26 +460,115 @@ class ReportmeTest < Test::Unit::TestCase
|
|
412
460
|
end
|
413
461
|
|
414
462
|
should "fail when multiple init blocks are defined" do
|
415
|
-
|
463
|
+
|
416
464
|
rme = create_visit_report_factory
|
417
|
-
rme.init do
|
418
|
-
end
|
419
465
|
|
420
466
|
assert_raise RuntimeError do
|
421
|
-
rme.init do
|
467
|
+
rme.class.init do
|
422
468
|
end
|
423
469
|
end
|
424
470
|
end
|
425
471
|
|
426
|
-
should "fail on
|
472
|
+
should "fail on non existing report dependencies" do
|
473
|
+
|
474
|
+
class ReportDependencyTestReport < Reportme::ReportFactory
|
475
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
476
|
+
report :report1 do
|
477
|
+
depends_on [:report2]
|
478
|
+
end
|
479
|
+
end
|
427
480
|
|
428
|
-
rme = create_visit_report_factory
|
429
|
-
# 'since' will be implicitly called by ower testing factory method above
|
430
|
-
# any further call should fails
|
431
|
-
|
432
481
|
assert_raise RuntimeError do
|
433
|
-
|
482
|
+
ReportDependencyTestReport.new.validate_dependencies
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
should "return a report by name" do
|
487
|
+
class ReportByNameTestReport < Reportme::ReportFactory
|
488
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
489
|
+
report :report1 do
|
490
|
+
end
|
491
|
+
report :report2 do
|
492
|
+
end
|
434
493
|
end
|
494
|
+
|
495
|
+
assert :report1, ReportByNameTestReport.report_by_name(:report1).name
|
496
|
+
assert :report2, ReportByNameTestReport.report_by_name(:report2).name
|
497
|
+
|
498
|
+
end
|
499
|
+
|
500
|
+
should "compute a dependency hash" do
|
501
|
+
class ReportDependencyHashTestReport < Reportme::ReportFactory
|
502
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
503
|
+
report :report1 do
|
504
|
+
depends_on [:report2, :report3]
|
505
|
+
end
|
506
|
+
report :report2 do
|
507
|
+
depends_on [:report3]
|
508
|
+
end
|
509
|
+
report :report3 do
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
hash = ReportDependencyHashTestReport.new.__dependency_hash
|
514
|
+
|
515
|
+
assert [
|
516
|
+
ReportDependencyHashTestReport.report_by_name(:report2),
|
517
|
+
ReportDependencyHashTestReport.report_by_name(:report3)
|
518
|
+
], hash[:report1]
|
519
|
+
|
520
|
+
assert [
|
521
|
+
ReportDependencyHashTestReport.report_by_name(:report3)
|
522
|
+
], hash[:report2]
|
523
|
+
|
524
|
+
assert [], hash[:report3]
|
525
|
+
end
|
526
|
+
|
527
|
+
should "sort some periods" do
|
528
|
+
assert [:day, :today], Reportme::ReportFactory.__sort_periods([{:name => :today}, {:name => :day}])
|
529
|
+
assert [:day, :week, :today], Reportme::ReportFactory.__sort_periods([{:name => :today}, {:name => :day}, {:name => :week}])
|
530
|
+
assert [:day, :week], Reportme::ReportFactory.__sort_periods([{:name => :week}, {:name => :day}])
|
531
|
+
assert [:day, :week, :month, :calendar_month, :today], Reportme::ReportFactory.__sort_periods([{:name => :week}, {:name => :day}, {:name => :today}, {:name => :calendar_month}, {:name => :month}])
|
532
|
+
|
533
|
+
assert [:day, :week, :week, :today, :today], Reportme::ReportFactory.__sort_periods([{:name => :week}, {:name => :today}, {:name => :today}, {:name => :week}, {:name => :day}])
|
534
|
+
end
|
535
|
+
|
536
|
+
should "run reports in a dependency aware manner" do
|
537
|
+
class ReportDependencyAwareTestReport < Reportme::ReportFactory
|
538
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
539
|
+
report :report1 do
|
540
|
+
depends_on [:report2, :report3]
|
541
|
+
end
|
542
|
+
report :report2 do
|
543
|
+
depends_on [:report3]
|
544
|
+
end
|
545
|
+
report :report3 do
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
runned = []
|
550
|
+
|
551
|
+
reports = []
|
552
|
+
reports << ReportDependencyAwareTestReport.report_by_name(:report1)
|
553
|
+
reports << ReportDependencyAwareTestReport.report_by_name(:report2)
|
554
|
+
reports << ReportDependencyAwareTestReport.report_by_name(:report3)
|
555
|
+
|
556
|
+
ReportDependencyAwareTestReport.new.run_dependency_aware(reports) do |report|
|
557
|
+
runned << report.name
|
558
|
+
end
|
559
|
+
|
560
|
+
assert [:report3, :report2, :report1], runned
|
561
|
+
|
562
|
+
end
|
563
|
+
|
564
|
+
should "prefix tablename with tmp_ for temporary reports" do
|
565
|
+
class ReportTemporaryTestReport < Reportme::ReportFactory
|
566
|
+
connection :adapter => "mysql", :database => "report_me_test", :username => "root", :password => "root", :host => "localhost", :port => 3306
|
567
|
+
report :report1, :temporary => true do
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
assert "tmp_report1_day", ReportTemporaryTestReport.report_by_name(:report1).table_name(:day)
|
435
572
|
end
|
436
573
|
|
437
574
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jzimmek-reportme
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Zimmek
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-29 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|