cubicle 0.1.30 → 0.1.31

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.
@@ -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