mochigome 0.1.13 → 0.1.14
Sign up to get free protection for your applications and to get access to all the features.
- data/TODO +1 -0
- data/lib/mochigome_ver.rb +1 -1
- data/lib/model_extensions.rb +25 -0
- data/lib/subgroup_model.rb +10 -4
- data/test/app_root/config/database-my.yml +1 -0
- data/test/app_root/db/migrate/20110817163830_create_tables.rb +1 -0
- data/test/factories.rb +1 -0
- data/test/unit/query_test.rb +18 -5
- metadata +14 -14
data/TODO
CHANGED
@@ -6,3 +6,4 @@
|
|
6
6
|
- Some kind of single-page preview on the edit screen would be cool. Maybe use FOP with fake data and the PNG output option?
|
7
7
|
- Automatically set default to 0 on sum and count aggregation
|
8
8
|
- Treat through-associations as hints for preferred paths
|
9
|
+
- Better handling of nil in subgroup fields
|
data/lib/mochigome_ver.rb
CHANGED
data/lib/model_extensions.rb
CHANGED
@@ -96,6 +96,9 @@ module Mochigome
|
|
96
96
|
# for this kind of stuff and also put the standard aggregation functions
|
97
97
|
# in there?
|
98
98
|
|
99
|
+
# FIXME All this lambda{|t| stuff is just needlessly confusing for
|
100
|
+
# the little good that it accomplishes.
|
101
|
+
|
99
102
|
def self.null_unless(pred, value_func)
|
100
103
|
case_expr(
|
101
104
|
lambda {|t| pred.call(value_func.call(t))},
|
@@ -114,6 +117,28 @@ module Mochigome
|
|
114
117
|
}
|
115
118
|
end
|
116
119
|
|
120
|
+
def self.multi_case_expr(cond_results, else_val = nil)
|
121
|
+
lambda {|t|
|
122
|
+
Arel::Nodes::SqlLiteral.new(
|
123
|
+
"(CASE " +
|
124
|
+
cond_results.map{|cond, result|
|
125
|
+
"WHEN #{arel_exprify(cond, t)} THEN #{arel_exprify(result, t)}"
|
126
|
+
} +
|
127
|
+
(else_val ? "ELSE #{arel_exprify(else_val, t)}" : "") +
|
128
|
+
"END)"
|
129
|
+
)
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.sql_bool_to_string(attr, prefix = "")
|
134
|
+
case_expr(
|
135
|
+
Arel::Nodes::NamedFunction.new('lower', [attr]).
|
136
|
+
in(["true", "t", 1, "1", "y", "yes"]),
|
137
|
+
"#{prefix}Yes",
|
138
|
+
"#{prefix}No"
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
117
142
|
private
|
118
143
|
|
119
144
|
def self.arel_exprify(e, t = nil)
|
data/lib/subgroup_model.rb
CHANGED
@@ -8,10 +8,15 @@ module Mochigome
|
|
8
8
|
def initialize(model, attr)
|
9
9
|
@model = model
|
10
10
|
@attr = attr
|
11
|
-
|
12
|
-
|
13
|
-
# @attr_expr will just be nil if there's no custom subgroup expr here
|
11
|
+
s = @model.mochigome_focus_settings
|
12
|
+
if s && s.options[:custom_subgroup_exprs][attr]
|
14
13
|
@attr_expr = s.options[:custom_subgroup_exprs][attr]
|
14
|
+
elsif @model.columns_hash[@attr.to_s].try(:type) == :boolean
|
15
|
+
@attr_expr = Mochigome::sql_bool_to_string(
|
16
|
+
model.arel_table[@attr], "#{human_name.titleize}: "
|
17
|
+
).call(model.arel_table)
|
18
|
+
else
|
19
|
+
@attr_expr = nil
|
15
20
|
end
|
16
21
|
@focus_settings = Mochigome::ReportFocusSettings.new(@model)
|
17
22
|
@focus_settings.type_name "#{@model.human_name} #{@attr.to_s.humanize}"
|
@@ -23,7 +28,8 @@ module Mochigome
|
|
23
28
|
end
|
24
29
|
|
25
30
|
def human_name
|
26
|
-
|
31
|
+
# Get rid of duplicate words (i.e. School$school_type)
|
32
|
+
"#{@model.human_name} #{@attr.to_s.humanize}".split.map(&:downcase).uniq.join(" ")
|
27
33
|
end
|
28
34
|
|
29
35
|
def real_model?
|
data/test/factories.rb
CHANGED
data/test/unit/query_test.rb
CHANGED
@@ -15,7 +15,8 @@ describe Mochigome::Query do
|
|
15
15
|
@john = create(:owner, :first_name => "John", :last_name => "Smith")
|
16
16
|
@store_x = create(:store, :name => "John's Store", :owner => @john)
|
17
17
|
|
18
|
-
@jane = create(:owner, :first_name => "Jane", :last_name => "Doe"
|
18
|
+
@jane = create(:owner, :first_name => "Jane", :last_name => "Doe",
|
19
|
+
:is_awesome => true)
|
19
20
|
@store_y = create(:store, :name => "Jane's Store (North)", :owner => @jane)
|
20
21
|
@store_z = create(:store, :name => "Jane's Store (South)", :owner => @jane)
|
21
22
|
|
@@ -180,6 +181,18 @@ describe Mochigome::Query do
|
|
180
181
|
assert_equal "Product A", (data_node/1/0/0/0).name
|
181
182
|
end
|
182
183
|
|
184
|
+
it "can subgroup layers by boolean attributes" do
|
185
|
+
q = Mochigome::Query.new(
|
186
|
+
[Mochigome::SubgroupModel.new(Owner, :is_awesome), Owner, Store, Product]
|
187
|
+
)
|
188
|
+
data_node = q.run
|
189
|
+
assert_equal "Owner Is Awesome: No", (data_node/0).name
|
190
|
+
assert_equal "John Smith", (data_node/0/0).name
|
191
|
+
assert_equal "John's Store", (data_node/0/0/0).name
|
192
|
+
assert_equal "Product A", (data_node/0/0/0/0).name
|
193
|
+
assert_equal "Owner Is Awesome: Yes", (data_node/1).name
|
194
|
+
end
|
195
|
+
|
183
196
|
it "can subgroup layers by attributes without including layer model" do
|
184
197
|
q = Mochigome::Query.new(
|
185
198
|
[Mochigome::SubgroupModel.new(Owner, :last_name)],
|
@@ -247,7 +260,7 @@ describe Mochigome::Query do
|
|
247
260
|
# Store X, Product C
|
248
261
|
assert_equal "Product C", (data_node/0/0/1).name
|
249
262
|
assert_equal 3, (data_node/0/0/1)['Sales count']
|
250
|
-
assert_equal (3*@product_c.price).to_s, (data_node/0/0/1)['Gross'].to_s
|
263
|
+
assert_equal (3*@product_c.price).to_f.to_s, (data_node/0/0/1)['Gross'].to_f.to_s
|
251
264
|
# Store Z, Product C
|
252
265
|
assert_equal "Product C", (data_node/1/1/0).name
|
253
266
|
assert_equal 2, (data_node/1/1/0)['Sales count']
|
@@ -259,7 +272,7 @@ describe Mochigome::Query do
|
|
259
272
|
# Store Z, Product C
|
260
273
|
assert_equal "Product C", (data_node/1/0/0).name
|
261
274
|
assert_equal 2, (data_node/1/0/0)['Sales count']
|
262
|
-
assert_equal (2*@product_c.price).to_s, (data_node/1/0/0)['Gross'].to_s
|
275
|
+
assert_equal (2*@product_c.price).to_f.to_s, (data_node/1/0/0)['Gross'].to_f.to_s
|
263
276
|
end
|
264
277
|
|
265
278
|
it "collects aggregate data in subgroups" do
|
@@ -369,8 +382,8 @@ describe Mochigome::Query do
|
|
369
382
|
data_node = q.run()
|
370
383
|
assert_equal "John's Store", (data_node/0/0).name
|
371
384
|
assert_equal 8, (data_node/0/0)['Sales count']
|
372
|
-
assert_equal (5*@product_a.price + 3*@product_c.price).to_s,
|
373
|
-
(data_node/0/0)['Gross'].to_s
|
385
|
+
assert_equal (5*@product_a.price + 3*@product_c.price).to_f.to_s,
|
386
|
+
(data_node/0/0)['Gross'].to_f.to_s
|
374
387
|
end
|
375
388
|
|
376
389
|
it "can do conditional counts" do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mochigome
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 14
|
10
|
+
version: 0.1.14
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- David Mike Simon
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-06-03 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
@@ -28,10 +28,10 @@ dependencies:
|
|
28
28
|
- 2
|
29
29
|
- 1
|
30
30
|
version: "2.1"
|
31
|
-
requirement: *id001
|
32
|
-
prerelease: false
|
33
31
|
type: :runtime
|
32
|
+
requirement: *id001
|
34
33
|
name: arel
|
34
|
+
prerelease: false
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
version_requirements: &id002 !ruby/object:Gem::Requirement
|
37
37
|
none: false
|
@@ -42,10 +42,10 @@ dependencies:
|
|
42
42
|
segments:
|
43
43
|
- 0
|
44
44
|
version: "0"
|
45
|
-
requirement: *id002
|
46
|
-
prerelease: false
|
47
45
|
type: :runtime
|
46
|
+
requirement: *id002
|
48
47
|
name: ruport
|
48
|
+
prerelease: false
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
version_requirements: &id003 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
segments:
|
57
57
|
- 0
|
58
58
|
version: "0"
|
59
|
-
requirement: *id003
|
60
|
-
prerelease: false
|
61
59
|
type: :runtime
|
60
|
+
requirement: *id003
|
62
61
|
name: nokogiri
|
62
|
+
prerelease: false
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
64
|
version_requirements: &id004 !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
@@ -70,10 +70,10 @@ dependencies:
|
|
70
70
|
segments:
|
71
71
|
- 0
|
72
72
|
version: "0"
|
73
|
-
requirement: *id004
|
74
|
-
prerelease: false
|
75
73
|
type: :runtime
|
74
|
+
requirement: *id004
|
76
75
|
name: rgl
|
76
|
+
prerelease: false
|
77
77
|
- !ruby/object:Gem::Dependency
|
78
78
|
version_requirements: &id005 !ruby/object:Gem::Requirement
|
79
79
|
none: false
|
@@ -84,10 +84,10 @@ dependencies:
|
|
84
84
|
segments:
|
85
85
|
- 0
|
86
86
|
version: "0"
|
87
|
-
requirement: *id005
|
88
|
-
prerelease: false
|
89
87
|
type: :runtime
|
88
|
+
requirement: *id005
|
90
89
|
name: activerecord
|
90
|
+
prerelease: false
|
91
91
|
description: Report generator that graphs over ActiveRecord associations
|
92
92
|
email: david.mike.simon@gmail.com
|
93
93
|
executables: []
|