cubicle 0.1.30 → 0.1.31

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,136 +1,143 @@
1
- module Cubicle
2
- module Aggregation
3
- module Dsl
4
-
5
- def source_collection_name(collection_name = nil)
6
- return @source_collection = collection_name if collection_name
7
- @source_collection ||= name.chomp("Cubicle").chomp("Cube").chomp("Aggregation").underscore.pluralize
8
- end
9
- alias source_collection_name= source_collection_name
10
-
11
- def target_collection_name(collection_name = nil)
12
- return nil if transient?
13
- return @target_name = collection_name if collection_name
14
- @target_name ||= "cubicle.fact.#{name.blank? ? source_collection_name : name.underscore}"
15
- end
16
- alias target_collection_name= target_collection_name
17
-
18
- def dimension(*args)
19
- dimensions << Cubicle::Dimension.new(*args)
20
- dimensions[-1]
21
- end
22
-
23
- def named_expressions
24
- return @named_expressions ||= OrderedHashWithIndifferentAccess.new
25
- end
26
-
27
- def dimensions(*args)
28
- return (@dimensions ||= Cubicle::MemberList.new) if args.length < 1
29
- args = args[0] if args.length == 1 && args[0].is_a?(Array)
30
- args.each {|dim| dimension dim }
31
- @dimensions
32
- end
33
-
34
- def measure(*args)
35
- measures << Measure.new(*args)
36
- measures[-1]
37
- end
38
-
39
- def measures(*args)
40
- return (@measures ||= Cubicle::MemberList.new) if args.length < 1
41
- args = args[0] if args.length == 1 && args[0].is_a?(Array)
42
- args.each {|m| measure m}
43
- @measures
44
- end
45
-
46
- def count(*args)
47
- options = args.extract_options!
48
- options[:aggregation_method] = :count
49
- measure(*(args << options))
50
- end
51
-
52
- def average(*args)
53
- options = args.extract_options!
54
- options[:aggregation_method] = :average
55
- measure(*(args << options))
56
- #Averaged fields need a count of non-null values to properly calculate the average
57
- args[0] = "#{args[0]}_count".to_sym
58
- count *args
59
- end
60
- alias avg average
61
-
62
- def sum(*args)
63
- options = args.extract_options!
64
- options[:aggregation_method] = :sum
65
- measure(*(args << options))
66
- end
67
-
68
- def duration(*args)
69
- options = args.extract_options!
70
- options[:in] ||= durations_in
71
- args << options
72
- measures << (dur = Duration.new(*args))
73
- count("#{dur.name}_count".to_sym, :expression=>dur.expression, :condition=>dur.condition) if dur.aggregation_method == :average
74
- end
75
-
76
- def average_duration(*args)
77
- duration(*args)
78
- end
79
- alias avg_duration average_duration
80
-
81
- def total_duration(*args)
82
- options = args.extract_options!
83
- options[:aggregation_method] = :sum
84
- duration(*(args<<options))
85
- end
86
-
87
- def duration_since(*args)
88
- options = args.extract_options!
89
- ms1 = args.length > 1 ? args.delete_at(1) : args.shift
90
- options[ms1] = :now
91
- duration(*(args<<options))
92
- end
93
- alias age_since duration_since
94
- alias elapsed duration_since
95
-
96
- def durations_in(unit_of_time = nil)
97
- return (@duration_unit ||= :seconds) unless unit_of_time
98
- @duration_unit = unit_of_time.to_s.pluralize.to_sym
99
- end
100
- alias :duration_unit :durations_in
101
-
102
-
103
- def ratio(member_name, numerator, denominator)
104
- measures << Ratio.new(member_name, numerator, denominator)
105
- end
106
-
107
- def difference(member_name, left, right)
108
- measures << Difference.new(member_name,left,right)
109
- end
110
-
111
- def bucketize(dimension_name, source_measure_name, bucket_range, options={}, &block)
112
- source_measure = measures[source_measure_name]
113
- raise "#{source_measure_name} does not appear to be a valid measure name. bucketize/categorize declarations must be placed AFTER any measures it uses have been defined." unless source_measure
114
- dimensions << BucketizedDimension.new(dimension_name, source_measure, bucket_range, options, &block)
115
- end
116
- alias categorize bucketize
117
-
118
- def aggregation(*member_list)
119
- member_list = member_list[0] if member_list[0].is_a?(Array)
120
- aggregations << member_list
121
- end
122
-
123
- def time_dimension(*args)
124
- return (@time_dimension ||= nil) unless args.length > 0
125
- @time_dimension = dimension(*args)
126
- end
127
- alias time_dimension= time_dimension
128
- alias date time_dimension
129
- alias time time_dimension
130
-
131
- def define(name,expression)
132
- named_expressions[name] = expression
133
- end
134
- end
135
- end
1
+ module Cubicle
2
+ module Aggregation
3
+ module Dsl
4
+
5
+ def source_collection_name(collection_name = nil, query={})
6
+ filter query unless query.blank?
7
+ return @source_collection = collection_name if collection_name
8
+ @source_collection ||= name.chomp("Cubicle").chomp("Cube").chomp("Aggregation").underscore.pluralize
9
+ end
10
+ alias source_collection_name= source_collection_name
11
+ alias source_collection source_collection_name
12
+
13
+ def target_collection_name(collection_name = nil)
14
+ return nil if transient?
15
+ return @target_name = collection_name if collection_name
16
+ @target_name ||= "cubicle.fact.#{name.blank? ? source_collection_name : name.underscore}"
17
+ end
18
+ alias target_collection_name= target_collection_name
19
+
20
+ def filter(query=nil)
21
+ return (@query ||= nil) unless query
22
+ @query = query
23
+ end
24
+
25
+ def dimension(*args)
26
+ dimensions << Cubicle::Dimension.new(*args)
27
+ dimensions[-1]
28
+ end
29
+
30
+ def named_expressions
31
+ return @named_expressions ||= OrderedHashWithIndifferentAccess.new
32
+ end
33
+
34
+ def dimensions(*args)
35
+ return (@dimensions ||= Cubicle::MemberList.new) if args.length < 1
36
+ args = args[0] if args.length == 1 && args[0].is_a?(Array)
37
+ args.each {|dim| dimension dim }
38
+ @dimensions
39
+ end
40
+
41
+ def measure(*args)
42
+ measures << Measure.new(*args)
43
+ measures[-1]
44
+ end
45
+
46
+ def measures(*args)
47
+ return (@measures ||= Cubicle::MemberList.new) if args.length < 1
48
+ args = args[0] if args.length == 1 && args[0].is_a?(Array)
49
+ args.each {|m| measure m}
50
+ @measures
51
+ end
52
+
53
+ def count(*args)
54
+ options = args.extract_options!
55
+ options[:aggregation_method] = :count
56
+ measure(*(args << options))
57
+ end
58
+
59
+ def average(*args)
60
+ options = args.extract_options!
61
+ options[:aggregation_method] = :average
62
+ measure(*(args << options))
63
+ #Averaged fields need a count of non-null values to properly calculate the average
64
+ args[0] = "#{args[0]}_count".to_sym
65
+ count *args
66
+ end
67
+ alias avg average
68
+
69
+ def sum(*args)
70
+ options = args.extract_options!
71
+ options[:aggregation_method] = :sum
72
+ measure(*(args << options))
73
+ end
74
+
75
+ def duration(*args)
76
+ options = args.extract_options!
77
+ options[:in] ||= durations_in
78
+ args << options
79
+ measures << (dur = Duration.new(*args))
80
+ count("#{dur.name}_count".to_sym, :expression=>dur.expression, :condition=>dur.condition) if dur.aggregation_method == :average
81
+ end
82
+
83
+ def average_duration(*args)
84
+ duration(*args)
85
+ end
86
+ alias avg_duration average_duration
87
+
88
+ def total_duration(*args)
89
+ options = args.extract_options!
90
+ options[:aggregation_method] = :sum
91
+ duration(*(args<<options))
92
+ end
93
+
94
+ def duration_since(*args)
95
+ options = args.extract_options!
96
+ ms1 = args.length > 1 ? args.delete_at(1) : args.shift
97
+ options[ms1] = :now
98
+ duration(*(args<<options))
99
+ end
100
+ alias age_since duration_since
101
+ alias elapsed duration_since
102
+
103
+ def durations_in(unit_of_time = nil)
104
+ return (@duration_unit ||= :seconds) unless unit_of_time
105
+ @duration_unit = unit_of_time.to_s.pluralize.to_sym
106
+ end
107
+ alias :duration_unit :durations_in
108
+
109
+
110
+ def ratio(member_name, numerator, denominator)
111
+ measures << Ratio.new(member_name, numerator, denominator)
112
+ end
113
+
114
+ def difference(member_name, left, right)
115
+ measures << Difference.new(member_name,left,right)
116
+ end
117
+
118
+ def bucketize(dimension_name, source_measure_name, bucket_range, options={}, &block)
119
+ source_measure = measures[source_measure_name]
120
+ raise "#{source_measure_name} does not appear to be a valid measure name. bucketize/categorize declarations must be placed AFTER any measures it uses have been defined." unless source_measure
121
+ dimensions << BucketizedDimension.new(dimension_name, source_measure, bucket_range, options, &block)
122
+ end
123
+ alias categorize bucketize
124
+
125
+ def aggregation(*member_list)
126
+ member_list = member_list[0] if member_list[0].is_a?(Array)
127
+ aggregations << member_list
128
+ end
129
+
130
+ def time_dimension(*args)
131
+ return (@time_dimension ||= nil) unless args.length > 0
132
+ @time_dimension = dimension(*args)
133
+ end
134
+ alias time_dimension= time_dimension
135
+ alias date time_dimension
136
+ alias time time_dimension
137
+
138
+ def define(name,expression)
139
+ named_expressions[name] = expression
140
+ end
141
+ end
142
+ end
136
143
  end
@@ -1,3 +1,3 @@
1
1
  module Cubicle
2
- VERSION = '0.1.30'
2
+ VERSION = '0.1.31'
3
3
  end
@@ -5,6 +5,7 @@ class AdHocTest < ActiveSupport::TestCase
5
5
  setup do
6
6
  Defect.create_test_data
7
7
  @results = Cubicle::Aggregation::AdHoc.new("defects") do
8
+ filter :account_id=>"a1"
8
9
  dimension :product, :field_name=>"product.name"
9
10
  count :total, :field_name=>"defect_id"
10
11
  end.query
@@ -1,486 +1,488 @@
1
- require "test_helper"
2
-
3
- class CubicleQueryTest < ActiveSupport::TestCase
4
- context "CubicleQuery#select" do
5
- setup do
6
- Defect.create_test_data
7
- end
8
- should "raise an exception when given a non-existent member" do
9
- assert_raise RuntimeError do
10
- DefectCubicle.query do
11
- select :does_not_exist
12
- end
13
- end
14
- end
15
- should "query the underlying data source of cubicle rather than the persistent cache when :transient=>true" do
16
- query = DefectCubicle.query :defer=>true do
17
- transient!
18
- select :product, :total_defects
19
- end
20
- query.execute()
21
- assert_equal "defects", query.source_collection_name
22
- end
23
- should "query the persistent cache when transient=>false" do
24
- query = DefectCubicle.query :defer=>true do
25
- select :product, :total_defects
26
- end
27
- query.execute()
28
- assert query.source_collection_name =~ /cubicle.aggregation.DefectCubicle._+/
29
- end
30
- should "Select dimensions in the by clause" do
31
- query_results = DefectCubicle.query do
32
- select :all_measures
33
- by :product
34
- end
35
- assert_equal :product, query_results.name
36
- assert_equal "Brush Fire Bottle Rockets", query_results.member_names[0]
37
- end
38
- should "Select aliased dimensions in the by clause" do
39
- query_results = DefectCubicle.query do
40
- select :all_measures
41
- by :date
42
- end
43
- assert_equal :manufacture_date, query_results.name
44
- assert_equal "2009-12-09", query_results.member_names[0]
45
- end
46
- context "when specifying a dimension" do
47
- setup do
48
- @results = DefectCubicle.query(:product, :all_measures)
49
- end
50
- should "return the specified subset of data, including all measures" do
51
- assert_equal 3, @results.length
52
-
53
- assert_equal "Brush Fire Bottle Rockets", @results[0]["product"]
54
- assert_equal 1, @results[0]["total_defects"]
55
- assert_equal 0, @results[0]["preventable_defects"]
56
- assert_equal 0.43, @results[0]["total_cost"]
57
- assert_equal 0.43, @results[0]["avg_cost"]
58
- assert_equal 0, @results[0]["preventable_pct"]
59
- end
60
-
61
- end
62
- context "when specifying a dimension using an alias" do
63
- setup do
64
- @results = DefectCubicle.query(:date, :all_measures)
65
- end
66
- should "return the specified subset of data, including all measures" do
67
- assert_equal 4, @results.length
68
- assert_equal "2009-12-09", @results[0]["date"]
69
- assert_equal 1, @results[0]["total_defects"]
70
- assert_equal 0, @results[0]["preventable_defects"]
71
- assert_equal 0.43, @results[0]["total_cost"]
72
- assert_equal 0.43, @results[0]["avg_cost"]
73
- assert_equal 0, @results[0]["preventable_pct"]
74
- end
75
- end
76
- context "when specifying a dimension from a transient query" do
77
- setup do
78
- #DefectCubicle.transient!
79
- @results = DefectCubicle.query do |q|
80
- q.transient!
81
- q.select :product, :all_measures
82
- end
83
- end
84
- should "return the specified subset of data, including all measures" do
85
- assert_equal 3, @results.length
86
-
87
- assert_equal "Brush Fire Bottle Rockets", @results[0]["product"]
88
- assert_equal 1, @results[0]["total_defects"]
89
- assert_equal 0, @results[0]["preventable_defects"]
90
- assert_equal 0.43, @results[0]["total_cost"]
91
- assert_equal 0.43, @results[0]["avg_cost"]
92
- assert_equal 0, @results[0]["preventable_pct"]
93
- end
94
-
95
- end
96
- context "when specifying a dimensional filter on a transient query" do
97
- setup do
98
- @results = DefectCubicle.query do
99
- transient!
100
- select :product, :all_measures
101
- where :product=>"Sad Day Moonshine"
102
- end
103
- end
104
- should "return a filtered subset of data" do
105
- assert_equal 1, @results.length
106
- assert_equal "Sad Day Moonshine", @results[0]["product"]
107
- assert_equal 3, @results[0]["total_defects"]
108
- assert_equal 2, @results[0]["preventable_defects"]
109
- assert_equal 2, @results[0]["conditioned_preventable"]
110
- assert_equal 21.63, @results[0]["total_cost"]
111
- assert_equal 21.63/3, @results[0]["avg_cost"]
112
- assert_equal 2/3.0, @results[0]["preventable_pct"]
113
- end
114
-
115
- end
116
- context "when specifying a dimensional filter on a transient query using an alias" do
117
- setup do
118
- #DefectCubicle.transient!
119
- @results = DefectCubicle.query do
120
- transient!
121
- select :manufacture_date, :all_measures
122
-
123
- where :date=>"2009-12-09"
124
- end
125
- end
126
- should "return a filtered subset of data" do
127
- assert_equal 1, @results.length
128
- assert_equal "2009-12-09", @results[0]["manufacture_date"]
129
- assert_equal 1, @results[0]["total_defects"]
130
- assert_equal 0, @results[0]["preventable_defects"]
131
- assert_equal 0.43, @results[0]["total_cost"]
132
- assert_equal 0.43, @results[0]["avg_cost"]
133
- assert_equal 0, @results[0]["preventable_pct"]
134
- end
135
-
136
- end
137
- context "when specifying a dimensional filter on a non-transient query" do
138
- setup do
139
- @results = DefectCubicle.query do
140
- select :product, :all_measures
141
- where :product=>"Sad Day Moonshine"
142
- end
143
- end
144
- should "return a filtered subset of data" do
145
- assert_equal 1, @results.length
146
- assert_equal "Sad Day Moonshine", @results[0]["product"]
147
- assert_equal 3, @results[0]["total_defects"]
148
- assert_equal 2, @results[0]["preventable_defects"]
149
- assert_equal 2, @results[0]["conditioned_preventable"]
150
- assert_in_delta 21.63, @results[0]["total_cost"],0.0001
151
- assert_in_delta 21.63/3, @results[0]["avg_cost"],0.0001
152
- assert_in_delta 2/3.0, @results[0]["preventable_pct"],0.0001
153
- end
154
-
155
- end
156
- context "when specifying a dimensional filter on a non-transient query using an alias" do
157
- setup do
158
- @results = DefectCubicle.query do
159
- select :date, :all_measures
160
- where :date=>"2009-12-09"
161
- end
162
- end
163
- should "return a filtered subset of data" do
164
- assert_equal 1, @results.length
165
- assert_equal "2009-12-09", @results[0]["manufacture_date"]
166
- assert_equal "2009-12-09", @results[0]["date"]
167
- assert_equal 1, @results[0]["total_defects"]
168
- assert_equal 0, @results[0]["preventable_defects"]
169
- assert_equal 0.43, @results[0]["total_cost"]
170
- assert_equal 0.43, @results[0]["avg_cost"]
171
- assert_equal 0, @results[0]["preventable_pct"]
172
- end
173
-
174
- end
175
- context "when specifying a dimensional filter on a non-transient query using $where" do
176
- setup do
177
- @results = DefectCubicle.query do
178
- select :product, :all_measures
179
- where "$where"=>"this._id.product=='Sad Day Moonshine'"
180
- end
181
- end
182
- should "return a filtered subset of data" do
183
- assert_equal 1, @results.length
184
- assert_equal "Sad Day Moonshine", @results[0]["product"]
185
- assert_equal 3, @results[0]["total_defects"]
186
- assert_equal 2, @results[0]["preventable_defects"]
187
- assert_equal 2, @results[0]["conditioned_preventable"]
188
- assert_in_delta 21.63, @results[0]["total_cost"],0.0001
189
- assert_in_delta 21.63/3, @results[0]["avg_cost"],0.0001
190
- assert_equal 2/3.0, @results[0]["preventable_pct"]
191
- end
192
-
193
- end
194
- context "when specifying a dimensional filter on a transient query using $where" do
195
- setup do
196
- @results = DefectCubicle.query do
197
- transient!
198
- select :product, :all_measures
199
- where "$where"=>"this.product.name=='Sad Day Moonshine'"
200
- end
201
- end
202
- should "return a filtered subset of data" do
203
- assert_equal 1, @results.length
204
- assert_equal "Sad Day Moonshine", @results[0]["product"]
205
- assert_equal 3, @results[0]["total_defects"]
206
- assert_equal 2, @results[0]["preventable_defects"]
207
- assert_equal 2, @results[0]["conditioned_preventable"]
208
- assert_equal 21.63, @results[0]["total_cost"]
209
- assert_equal 21.63/3, @results[0]["avg_cost"]
210
- assert_equal 2/3.0, @results[0]["preventable_pct"]
211
- end
212
-
213
- end
214
- context "when specifying a dimensional filter for an expression based dimension on a transient query" do
215
- setup do
216
- @results = DefectCubicle.query do
217
- transient!
218
- select :product,:all_measures
219
- where :month=>"2010-01"
220
- end
221
- end
222
- should "return a filtered subset of data" do
223
- assert_equal 2, @results.length
224
- assert_equal "Evil's Pickling Spice", @results[0]["product"]
225
- assert_equal "Sad Day Moonshine", @results[1]["product"]
226
- end
227
- end
228
- context "when specifying a special dimensional filter for an expression based dimension on a transient query" do
229
- setup do
230
- @results = DefectCubicle.query do
231
- transient!
232
- select :product,:all_measures
233
- where :month=>{"$ne"=>"2010-01"}
234
- end
235
- end
236
- should "return a filtered subset of data" do
237
- assert_equal 2, @results.length
238
- assert_equal "Brush Fire Bottle Rockets", @results[0]["product"]
239
- assert_equal "Sad Day Moonshine", @results[1]["product"]
240
- end
241
- end
242
- context "when specifying several special dimensional filters for an expression based dimension on a transient query" do
243
- setup do
244
- @results = DefectCubicle.query do
245
- transient!
246
- select :product,:all_measures
247
- where :month=>{"$gt"=>"2010-01", "$lte"=>"2010-02"}
248
- end
249
- end
250
- should "return a filtered subset of data" do
251
- assert_equal 1, @results.length
252
- assert_equal "Sad Day Moonshine", @results[0]["product"]
253
- end
254
- end
255
- context "when specifying a special dimensional filter for an expression based bucketized dimension on a transient query" do
256
- setup do
257
- @results = DefectCubicle.query do
258
- transient!
259
- select :product, :all_measures
260
- where :avg_cost_category=>{"$ne"=>"< $1"}
261
- end
262
- end
263
- should "return a filtered subset of data" do
264
- puts @results.inspect
265
- assert_equal 1, @results.length
266
- end
267
- end
268
- context "when specifying a sort order on a transient query" do
269
- setup do
270
- @results = DefectCubicle.query do
271
- transient!
272
- select :product,:all_measures
273
- order_by [:product, :desc]
274
- end
275
- end
276
- should "return sorted data" do
277
- assert_equal 3, @results.length
278
- assert_equal "Sad Day Moonshine", @results[0]["product"]
279
- assert_equal "Evil's Pickling Spice", @results[1]["product"]
280
- assert_equal "Brush Fire Bottle Rockets", @results[2]["product"]
281
- end
282
-
283
- end
284
- context "when specifying a sort order on a non transient query" do
285
- setup do
286
- @results = DefectCubicle.query do
287
- select :product,:all_measures
288
- order_by [:product, :desc]
289
- end
290
- end
291
- should "return sorted data" do
292
- assert_equal 3, @results.length
293
- assert_equal "Sad Day Moonshine", @results[0]["product"]
294
- assert_equal "Evil's Pickling Spice", @results[1]["product"]
295
- assert_equal "Brush Fire Bottle Rockets", @results[2]["product"]
296
- end
297
-
298
- end
299
- context "when requesting YTD" do
300
- setup do
301
- Time.now = "2010-01-04"
302
- @results = DefectCubicle.query do
303
- select :date, :all_measures
304
- year_to_date
305
- end
306
- end
307
- should "present YTD data based on Time.now" do
308
- assert_equal 1, @results.length
309
- assert_in_delta 18.69, @results[0]["total_cost"],0.0001
310
- end
311
- end
312
- context "when requesting MTD in a non-transient query do" do
313
- setup do
314
- Time.now = "2010-01-05"
315
- @results = DefectCubicle.query do
316
- select :month, :all_measures
317
- month_to_date
318
- end
319
- end
320
- should "present MTD data based on Time.now" do
321
- assert_equal 1, @results.length
322
- assert_in_delta 18.71, @results[0]["total_cost"],0.0001
323
- end
324
- end
325
- context "when requesting MTD in a transient query do" do
326
- setup do
327
- Time.now = "2010-01-05"
328
- @results = DefectCubicle.query do
329
- transient!
330
- select :month, :all_measures
331
- month_to_date
332
- end
333
- end
334
- should "present MTD data based on Time.now" do
335
- assert_equal 1, @results.length
336
- assert_in_delta 18.71, @results[0]["total_cost"],0.0001
337
- end
338
- end
339
- context "when requesting for_the_last_complete 1.months" do
340
- setup do
341
- Time.now = "2010-01-30"
342
- @results = DefectCubicle.query do
343
- select :month, :all_measures
344
- for_the_last_complete :month
345
- end
346
- end
347
- should "present data for the previous month" do
348
- assert_equal 1, @results.length
349
- assert_equal 0.43, @results[0]["total_cost"]
350
- end
351
- end
352
- context "when requesting an exclusive date range" do
353
- setup do
354
- Time.now = "2010-01-30"
355
- @results = DefectCubicle.query do
356
- select :month, :all_measures
357
- for_the_last_complete 12.months
358
- by :month
359
- end
360
- end
361
- should "provide an entry for each month, even months without data" do
362
- assert_equal [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0], @results.flatten(:total_defects)
363
- assert_equal "2009-01", @results.keys[0]
364
- assert_equal "2009-12", @results.keys[-1]
365
- end
366
- end
367
- context "when requesting a date range with no results" do
368
- setup do
369
- Time.now = "2020-01-01"
370
- @results = DefectCubicle.query do
371
- select :month, :all_measures
372
- for_the_last_complete 12.months
373
- by :month
374
- end
375
- end
376
- should "provide an empty entry for each month" do
377
- assert_equal 12, @results.count
378
- assert_equal [0,0,0,0,0,0,0,0,0,0,0,0], @results.flatten(:total_defects)
379
- end
380
- end
381
- context "Date filters against native Time types" do
382
- setup do
383
- Time.now = "2010-01-30"
384
- Cubicle::DateTime.db_time_format = :native
385
- @results = DefectCubicle.query do
386
- time_dimension :manufacture_time
387
- select :month, :all_measures
388
- for_the_last_complete :month
389
- end
390
- end
391
- should "dance like a butterfly and sting like a bee" do
392
- assert_equal 1, @results.length
393
- assert_equal 0.43, @results[0]["total_cost"]
394
- end
395
- teardown do
396
- Cubicle::DateTime.db_time_format = :iso8601
397
- end
398
- end
399
- context "when a query level alias has been specified" do
400
- should "respect the alias in the by clause" do
401
- query_results = DefectCubicle.query do
402
- alias_member :date=>:my_crazy_date
403
- select :all_measures
404
- by :my_crazy_date
405
- end
406
- assert_equal :manufacture_date, query_results.name
407
- assert_equal "2009-12-09", query_results.member_names[0]
408
- end
409
- should "respect the alias in the where clause" do
410
- results = DefectCubicle.query do
411
- alias_member :product=>:my_crazy_product
412
- select :product, :all_measures
413
- where :my_crazy_product=>"Sad Day Moonshine"
414
- end
415
- assert_equal 1, results.length
416
- assert_equal "Sad Day Moonshine", results[0]["product"]
417
- assert_equal "Sad Day Moonshine", results[0]["my_crazy_product"]
418
- assert_equal 3, results[0]["total_defects"]
419
- assert_equal 2, results[0]["preventable_defects"]
420
- assert_equal 2, results[0]["conditioned_preventable"]
421
- assert_in_delta 21.63, results[0]["total_cost"],0.0001
422
- assert_in_delta 21.63/3, results[0]["avg_cost"],0.0001
423
- assert_in_delta 2/3.0, results[0]["preventable_pct"],0.0001
424
- end
425
- should "respect the alias in the order by clause" do
426
- results = DefectCubicle.query do
427
- alias_member :product=>:my_crazy_product
428
- select :product,:all_measures
429
- order_by [:my_crazy_product, :desc]
430
- end
431
- assert_equal 3, results.length
432
- assert_equal "Sad Day Moonshine", results[0]["product"]
433
- assert_equal "Evil's Pickling Spice", results[1]["product"]
434
- assert_equal "Brush Fire Bottle Rockets", results[2]["product"]
435
- end
436
- should "calculate distinct counts properly" do
437
- results = DefectCubicle.query do
438
- select :year, :distinct_products
439
- where :year=>"2010"
440
- end
441
- puts results.inspect
442
- assert_equal 1, results.length
443
- assert_equal 2, results[0]["distinct_products"]
444
- end
445
- end
446
- context "Aggregation level 'define' calls" do
447
- should "override the default of Time.now" do
448
- results = DefectCubicle.query do
449
- transient!
450
- select :year, :defects_this_year
451
- end
452
- puts results.inspect
453
- assert_equal 2, results.length
454
- assert_equal 0, results[0].defects_this_year
455
- assert_equal 4, results[1].defects_this_year
456
- end
457
- end
458
- context "Query level 'define' calls" do
459
- should "override the defaults" do
460
- results = DefectCubicle.query do
461
- transient!
462
- define :time_now, "2009-01-01".to_time
463
-
464
- select :year, :defects_this_year
465
- end
466
- puts results.inspect
467
- assert_equal 2, results.length
468
- assert_equal 1, results[0].defects_this_year
469
- assert_equal 0, results[1].defects_this_year
470
- end
471
- end
472
- context "Grouping by day" do
473
- should "not cause the system to hang" do
474
- Time.now = "2010-01-01"
475
- results = DefectCubicle.query do
476
- select :defects_this_year
477
- by :date
478
- for_the_last 5.days
479
- end
480
- puts results.inspect
481
- assert_not_nil results
482
- end
483
-
484
- end
485
- end
1
+ require "test_helper"
2
+
3
+ class CubicleQueryTest < ActiveSupport::TestCase
4
+ context "CubicleQuery#select" do
5
+ setup do
6
+ Defect.create_test_data
7
+ end
8
+ should "raise an exception when given a non-existent member" do
9
+ assert_raise RuntimeError do
10
+ DefectCubicle.query do
11
+ select :does_not_exist
12
+ end
13
+ end
14
+ end
15
+ should "query the underlying data source of cubicle rather than the persistent cache when :transient=>true" do
16
+ query = DefectCubicle.query :defer=>true do
17
+ transient!
18
+ select :product, :total_defects
19
+ end
20
+ query.execute()
21
+ assert_equal "defects", query.source_collection_name
22
+ end
23
+ should "query the persistent cache when transient=>false" do
24
+ query = DefectCubicle.query :defer=>true do
25
+ select :product, :total_defects
26
+ end
27
+ query.execute()
28
+ assert query.source_collection_name =~ /cubicle.aggregation.DefectCubicle._+/
29
+ end
30
+ should "Select dimensions in the by clause" do
31
+ query_results = DefectCubicle.query do
32
+ select :all_measures
33
+ by :product
34
+ end
35
+ assert_equal :product, query_results.name
36
+ assert_equal "Brush Fire Bottle Rockets", query_results.member_names[0]
37
+ end
38
+ should "Select aliased dimensions in the by clause" do
39
+ query_results = DefectCubicle.query do
40
+ select :all_measures
41
+ by :date
42
+ end
43
+ assert_equal :manufacture_date, query_results.name
44
+ assert_equal "2009-12-09", query_results.member_names[0]
45
+ end
46
+ context "when specifying a dimension" do
47
+ setup do
48
+ @results = DefectCubicle.query(:product, :all_measures)
49
+ end
50
+ should "return the specified subset of data, including all measures" do
51
+ assert_equal 3, @results.length
52
+
53
+ assert_equal "Brush Fire Bottle Rockets", @results[0]["product"]
54
+ assert_equal 1, @results[0]["total_defects"]
55
+ assert_equal 0, @results[0]["preventable_defects"]
56
+ assert_equal 0.43, @results[0]["total_cost"]
57
+ assert_equal 0.43, @results[0]["avg_cost"]
58
+ assert_equal 0, @results[0]["preventable_pct"]
59
+ end
60
+
61
+ end
62
+ context "when specifying a dimension using an alias" do
63
+ setup do
64
+ @results = DefectCubicle.query(:date, :all_measures)
65
+ end
66
+ should "return the specified subset of data, including all measures" do
67
+ assert_equal 4, @results.length
68
+ assert_equal "2009-12-09", @results[0]["date"]
69
+ assert_equal 1, @results[0]["total_defects"]
70
+ assert_equal 0, @results[0]["preventable_defects"]
71
+ assert_equal 0.43, @results[0]["total_cost"]
72
+ assert_equal 0.43, @results[0]["avg_cost"]
73
+ assert_equal 0, @results[0]["preventable_pct"]
74
+ end
75
+ end
76
+ context "when specifying a dimension from a transient query" do
77
+ setup do
78
+ #DefectCubicle.transient!
79
+ @results = DefectCubicle.query do |q|
80
+ q.transient!
81
+ q.select :product, :all_measures
82
+ end
83
+ end
84
+ should "return the specified subset of data, including all measures" do
85
+ assert_equal 3, @results.length
86
+
87
+ assert_equal "Brush Fire Bottle Rockets", @results[0]["product"]
88
+ assert_equal 1, @results[0]["total_defects"]
89
+ assert_equal 0, @results[0]["preventable_defects"]
90
+ assert_equal 0.43, @results[0]["total_cost"]
91
+ assert_equal 0.43, @results[0]["avg_cost"]
92
+ assert_equal 0, @results[0]["preventable_pct"]
93
+ end
94
+
95
+ end
96
+ context "when specifying a dimensional filter on a transient query" do
97
+ setup do
98
+ @results = DefectCubicle.query do
99
+ transient!
100
+ select :product, :all_measures
101
+ where :product=>"Sad Day Moonshine"
102
+ end
103
+ end
104
+ should "return a filtered subset of data" do
105
+ assert_equal 1, @results.length
106
+ assert_equal "Sad Day Moonshine", @results[0]["product"]
107
+ assert_equal 3, @results[0]["total_defects"]
108
+ assert_equal 2, @results[0]["preventable_defects"]
109
+ assert_equal 2, @results[0]["conditioned_preventable"]
110
+ assert_equal 21.63, @results[0]["total_cost"]
111
+ assert_equal 21.63/3, @results[0]["avg_cost"]
112
+ assert_equal 2/3.0, @results[0]["preventable_pct"]
113
+ end
114
+
115
+ end
116
+ context "when specifying a dimensional filter on a transient query using an alias" do
117
+ setup do
118
+ #DefectCubicle.transient!
119
+ @results = DefectCubicle.query do
120
+ transient!
121
+ select :manufacture_date, :all_measures
122
+
123
+ where :date=>"2009-12-09"
124
+ end
125
+ end
126
+ should "return a filtered subset of data" do
127
+ assert_equal 1, @results.length
128
+ assert_equal "2009-12-09", @results[0]["manufacture_date"]
129
+ assert_equal 1, @results[0]["total_defects"]
130
+ assert_equal 0, @results[0]["preventable_defects"]
131
+ assert_equal 0.43, @results[0]["total_cost"]
132
+ assert_equal 0.43, @results[0]["avg_cost"]
133
+ assert_equal 0, @results[0]["preventable_pct"]
134
+ end
135
+
136
+ end
137
+ context "when specifying a dimensional filter on a non-transient query" do
138
+ setup do
139
+ @results = DefectCubicle.query do
140
+ select :product, :all_measures
141
+ where :product=>"Sad Day Moonshine"
142
+ end
143
+ end
144
+ should "return a filtered subset of data" do
145
+ assert_equal 1, @results.length
146
+ assert_equal "Sad Day Moonshine", @results[0]["product"]
147
+ assert_equal 3, @results[0]["total_defects"]
148
+ assert_equal 2, @results[0]["preventable_defects"]
149
+ assert_equal 2, @results[0]["conditioned_preventable"]
150
+ assert_in_delta 21.63, @results[0]["total_cost"],0.0001
151
+ assert_in_delta 21.63/3, @results[0]["avg_cost"],0.0001
152
+ assert_in_delta 2/3.0, @results[0]["preventable_pct"],0.0001
153
+ end
154
+
155
+ end
156
+ context "when specifying a dimensional filter on a non-transient query using an alias" do
157
+ setup do
158
+ @results = DefectCubicle.query do
159
+ select :date, :all_measures
160
+ where :date=>"2009-12-09"
161
+ end
162
+ end
163
+ should "return a filtered subset of data" do
164
+ assert_equal 1, @results.length
165
+ assert_equal "2009-12-09", @results[0]["manufacture_date"]
166
+ assert_equal "2009-12-09", @results[0]["date"]
167
+ assert_equal 1, @results[0]["total_defects"]
168
+ assert_equal 0, @results[0]["preventable_defects"]
169
+ assert_equal 0.43, @results[0]["total_cost"]
170
+ assert_equal 0.43, @results[0]["avg_cost"]
171
+ assert_equal 0, @results[0]["preventable_pct"]
172
+ end
173
+
174
+ end
175
+ context "when specifying a dimensional filter on a non-transient query using $where" do
176
+ setup do
177
+ @results = DefectCubicle.query do
178
+ select :product, :all_measures
179
+ where "$where"=>"this._id.product=='Sad Day Moonshine'"
180
+ end
181
+ end
182
+ should "return a filtered subset of data" do
183
+ assert_equal 1, @results.length
184
+ assert_equal "Sad Day Moonshine", @results[0]["product"]
185
+ assert_equal 3, @results[0]["total_defects"]
186
+ assert_equal 2, @results[0]["preventable_defects"]
187
+ assert_equal 2, @results[0]["conditioned_preventable"]
188
+ assert_in_delta 21.63, @results[0]["total_cost"],0.0001
189
+ assert_in_delta 21.63/3, @results[0]["avg_cost"],0.0001
190
+ assert_equal 2/3.0, @results[0]["preventable_pct"]
191
+ end
192
+
193
+ end
194
+ context "when specifying a dimensional filter on a transient query using $where" do
195
+ setup do
196
+ @results = DefectCubicle.query do
197
+ transient!
198
+ select :product, :all_measures
199
+ where "$where"=>"this.product.name=='Sad Day Moonshine'"
200
+ end
201
+ end
202
+ should "return a filtered subset of data" do
203
+ assert_equal 1, @results.length
204
+ assert_equal "Sad Day Moonshine", @results[0]["product"]
205
+ assert_equal 3, @results[0]["total_defects"]
206
+ assert_equal 2, @results[0]["preventable_defects"]
207
+ assert_equal 2, @results[0]["conditioned_preventable"]
208
+ assert_equal 21.63, @results[0]["total_cost"]
209
+ assert_equal 21.63/3, @results[0]["avg_cost"]
210
+ assert_equal 2/3.0, @results[0]["preventable_pct"]
211
+ end
212
+
213
+ end
214
+ context "when specifying a dimensional filter for an expression based dimension on a transient query" do
215
+ setup do
216
+ @results = DefectCubicle.query do
217
+ transient!
218
+ select :product,:all_measures
219
+ where :month=>"2010-01"
220
+ end
221
+ end
222
+ should "return a filtered subset of data" do
223
+ puts @results.inspect
224
+ assert_equal 2, @results.length
225
+ assert_equal "Evil's Pickling Spice", @results[0]["product"]
226
+ assert_equal "Sad Day Moonshine", @results[1]["product"]
227
+ end
228
+ end
229
+ context "when specifying a special dimensional filter for an expression based dimension on a transient query" do
230
+ setup do
231
+ @results = DefectCubicle.query do
232
+ transient!
233
+ select :product,:all_measures
234
+ where :month=>{"$ne"=>"2010-01"}
235
+ end
236
+ end
237
+ should "return a filtered subset of data" do
238
+ assert_equal 2, @results.length
239
+ assert_equal "Brush Fire Bottle Rockets", @results[0]["product"]
240
+ assert_equal "Sad Day Moonshine", @results[1]["product"]
241
+ end
242
+ end
243
+ context "when specifying several special dimensional filters for an expression based dimension on a transient query" do
244
+ setup do
245
+ @results = DefectCubicle.query do
246
+ transient!
247
+ select :product,:all_measures
248
+ where :month=>{"$gt"=>"2010-01", "$lte"=>"2010-02"}
249
+ end
250
+ end
251
+ should "return a filtered subset of data" do
252
+ assert_equal 1, @results.length
253
+ assert_equal "Sad Day Moonshine", @results[0]["product"]
254
+ end
255
+ end
256
+ context "when specifying a special dimensional filter for an expression based bucketized dimension on a transient query" do
257
+ setup do
258
+ @results = DefectCubicle.query do
259
+ transient!
260
+ select :product, :all_measures
261
+ where :avg_cost_category=>{"$ne"=>"< $1"}
262
+ end
263
+ end
264
+ should "return a filtered subset of data" do
265
+ puts @results.inspect
266
+ assert_equal 1, @results.length
267
+ end
268
+ end
269
+ context "when specifying a sort order on a transient query" do
270
+ setup do
271
+ @results = DefectCubicle.query do
272
+ transient!
273
+ select :product,:all_measures
274
+ order_by [:product, :desc]
275
+ end
276
+ end
277
+ should "return sorted data" do
278
+ assert_equal 3, @results.length
279
+ assert_equal "Sad Day Moonshine", @results[0]["product"]
280
+ assert_equal "Evil's Pickling Spice", @results[1]["product"]
281
+ assert_equal "Brush Fire Bottle Rockets", @results[2]["product"]
282
+ end
283
+
284
+ end
285
+ context "when specifying a sort order on a non transient query" do
286
+ setup do
287
+ @results = DefectCubicle.query do
288
+ select :product,:all_measures
289
+ order_by [:product, :desc]
290
+ end
291
+ end
292
+ should "return sorted data" do
293
+ assert_equal 3, @results.length
294
+ assert_equal "Sad Day Moonshine", @results[0]["product"]
295
+ assert_equal "Evil's Pickling Spice", @results[1]["product"]
296
+ assert_equal "Brush Fire Bottle Rockets", @results[2]["product"]
297
+ end
298
+
299
+ end
300
+ context "when requesting YTD" do
301
+ setup do
302
+ Time.now = "2010-01-04"
303
+ @results = DefectCubicle.query do
304
+ select :date, :all_measures
305
+ year_to_date
306
+ end
307
+ end
308
+ should "present YTD data based on Time.now" do
309
+ assert_equal 1, @results.length
310
+ assert_in_delta 18.69, @results[0]["total_cost"],0.0001
311
+ end
312
+ end
313
+ context "when requesting MTD in a non-transient query do" do
314
+ setup do
315
+ Time.now = "2010-01-05"
316
+ @results = DefectCubicle.query do
317
+ select :month, :all_measures
318
+ month_to_date
319
+ end
320
+ end
321
+ should "present MTD data based on Time.now" do
322
+ assert_equal 1, @results.length
323
+ assert_in_delta 18.71, @results[0]["total_cost"],0.0001
324
+ end
325
+ end
326
+ context "when requesting MTD in a transient query do" do
327
+ setup do
328
+ Time.now = "2010-01-05"
329
+ @results = DefectCubicle.query do
330
+ transient!
331
+ select :month, :all_measures
332
+ month_to_date
333
+ end
334
+ end
335
+ should "present MTD data based on Time.now" do
336
+ puts @results.inspect
337
+ assert_equal 1, @results.length
338
+ assert_in_delta 18.71, @results[0]["total_cost"],0.0001
339
+ end
340
+ end
341
+ context "when requesting for_the_last_complete 1.months" do
342
+ setup do
343
+ Time.now = "2010-01-30"
344
+ @results = DefectCubicle.query do
345
+ select :month, :all_measures
346
+ for_the_last_complete :month
347
+ end
348
+ end
349
+ should "present data for the previous month" do
350
+ assert_equal 1, @results.length
351
+ assert_equal 0.43, @results[0]["total_cost"]
352
+ end
353
+ end
354
+ context "when requesting an exclusive date range" do
355
+ setup do
356
+ Time.now = "2010-01-30"
357
+ @results = DefectCubicle.query do
358
+ select :month, :all_measures
359
+ for_the_last_complete 12.months
360
+ by :month
361
+ end
362
+ end
363
+ should "provide an entry for each month, even months without data" do
364
+ assert_equal [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0], @results.flatten(:total_defects)
365
+ assert_equal "2009-01", @results.keys[0]
366
+ assert_equal "2009-12", @results.keys[-1]
367
+ end
368
+ end
369
+ context "when requesting a date range with no results" do
370
+ setup do
371
+ Time.now = "2020-01-01"
372
+ @results = DefectCubicle.query do
373
+ select :month, :all_measures
374
+ for_the_last_complete 12.months
375
+ by :month
376
+ end
377
+ end
378
+ should "provide an empty entry for each month" do
379
+ assert_equal 12, @results.count
380
+ assert_equal [0,0,0,0,0,0,0,0,0,0,0,0], @results.flatten(:total_defects)
381
+ end
382
+ end
383
+ context "Date filters against native Time types" do
384
+ setup do
385
+ Time.now = "2010-01-30"
386
+ Cubicle::DateTime.db_time_format = :native
387
+ @results = DefectCubicle.query do
388
+ time_dimension :manufacture_time
389
+ select :month, :all_measures
390
+ for_the_last_complete :month
391
+ end
392
+ end
393
+ should "dance like a butterfly and sting like a bee" do
394
+ assert_equal 1, @results.length
395
+ assert_equal 0.43, @results[0]["total_cost"]
396
+ end
397
+ teardown do
398
+ Cubicle::DateTime.db_time_format = :iso8601
399
+ end
400
+ end
401
+ context "when a query level alias has been specified" do
402
+ should "respect the alias in the by clause" do
403
+ query_results = DefectCubicle.query do
404
+ alias_member :date=>:my_crazy_date
405
+ select :all_measures
406
+ by :my_crazy_date
407
+ end
408
+ assert_equal :manufacture_date, query_results.name
409
+ assert_equal "2009-12-09", query_results.member_names[0]
410
+ end
411
+ should "respect the alias in the where clause" do
412
+ results = DefectCubicle.query do
413
+ alias_member :product=>:my_crazy_product
414
+ select :product, :all_measures
415
+ where :my_crazy_product=>"Sad Day Moonshine"
416
+ end
417
+ assert_equal 1, results.length
418
+ assert_equal "Sad Day Moonshine", results[0]["product"]
419
+ assert_equal "Sad Day Moonshine", results[0]["my_crazy_product"]
420
+ assert_equal 3, results[0]["total_defects"]
421
+ assert_equal 2, results[0]["preventable_defects"]
422
+ assert_equal 2, results[0]["conditioned_preventable"]
423
+ assert_in_delta 21.63, results[0]["total_cost"],0.0001
424
+ assert_in_delta 21.63/3, results[0]["avg_cost"],0.0001
425
+ assert_in_delta 2/3.0, results[0]["preventable_pct"],0.0001
426
+ end
427
+ should "respect the alias in the order by clause" do
428
+ results = DefectCubicle.query do
429
+ alias_member :product=>:my_crazy_product
430
+ select :product,:all_measures
431
+ order_by [:my_crazy_product, :desc]
432
+ end
433
+ assert_equal 3, results.length
434
+ assert_equal "Sad Day Moonshine", results[0]["product"]
435
+ assert_equal "Evil's Pickling Spice", results[1]["product"]
436
+ assert_equal "Brush Fire Bottle Rockets", results[2]["product"]
437
+ end
438
+ should "calculate distinct counts properly" do
439
+ results = DefectCubicle.query do
440
+ select :year, :distinct_products
441
+ where :year=>"2010"
442
+ end
443
+ puts results.inspect
444
+ assert_equal 1, results.length
445
+ assert_equal 2, results[0]["distinct_products"]
446
+ end
447
+ end
448
+ context "Aggregation level 'define' calls" do
449
+ should "override the default of Time.now" do
450
+ results = DefectCubicle.query do
451
+ transient!
452
+ select :year, :defects_this_year
453
+ end
454
+ puts results.inspect
455
+ assert_equal 2, results.length
456
+ assert_equal 0, results[0].defects_this_year
457
+ assert_equal 4, results[1].defects_this_year
458
+ end
459
+ end
460
+ context "Query level 'define' calls" do
461
+ should "override the defaults" do
462
+ results = DefectCubicle.query do
463
+ transient!
464
+ define :time_now, "2009-01-01".to_time
465
+
466
+ select :year, :defects_this_year
467
+ end
468
+ puts results.inspect
469
+ assert_equal 2, results.length
470
+ assert_equal 1, results[0].defects_this_year
471
+ assert_equal 0, results[1].defects_this_year
472
+ end
473
+ end
474
+ context "Grouping by day" do
475
+ should "not cause the system to hang" do
476
+ Time.now = "2010-01-01"
477
+ results = DefectCubicle.query do
478
+ select :defects_this_year
479
+ by :date
480
+ for_the_last 5.days
481
+ end
482
+ puts results.inspect
483
+ assert_not_nil results
484
+ end
485
+
486
+ end
487
+ end
486
488
  end