mdquery 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +53 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +78 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/mdquery.rb +13 -0
- data/lib/mdquery/dataset.rb +283 -0
- data/lib/mdquery/dsl.rb +176 -0
- data/lib/mdquery/model.rb +270 -0
- data/lib/mdquery/util.rb +21 -0
- data/mdquery.gemspec +78 -0
- data/spec/mdquery/dataset_spec.rb +232 -0
- data/spec/mdquery/dsl_spec.rb +144 -0
- data/spec/mdquery/model_spec.rb +473 -0
- data/spec/mdquery/util_spec.rb +25 -0
- data/spec/mdquery_spec.rb +35 -0
- data/spec/spec_helper.rb +11 -0
- metadata +149 -0
@@ -0,0 +1,473 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'mdquery/model'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module MDQuery
|
6
|
+
module Model
|
7
|
+
describe CASTS do
|
8
|
+
it "sym cast should cast a string to a symbol" do
|
9
|
+
CASTS[:sym].call("blah").should == :blah
|
10
|
+
end
|
11
|
+
it "int cast should cast a string to a symbol" do
|
12
|
+
cv = CASTS[:int].call("100")
|
13
|
+
cv.should == 100
|
14
|
+
cv.class.should == 100.class
|
15
|
+
end
|
16
|
+
it "float cast should cast a string to a float" do
|
17
|
+
cv = CASTS[:float].call("3.5")
|
18
|
+
cv.should == 3.5
|
19
|
+
cv.class.should == 3.5.class
|
20
|
+
end
|
21
|
+
it "date cast should cast a string to a date" do
|
22
|
+
cv = CASTS[:date].call("2011-03-25")
|
23
|
+
cv.should == Date.parse("2011-03-25")
|
24
|
+
cv.class.should == Date
|
25
|
+
end
|
26
|
+
it "datetime cast should cast a string to a datetime" do
|
27
|
+
cv = CASTS[:datetime].call("2011-03-25 08:47:23")
|
28
|
+
cv.should == DateTime.parse("2011-03-25 08:47:23")
|
29
|
+
cv.class.should == DateTime
|
30
|
+
end
|
31
|
+
it "time cast should cast a string to a time" do
|
32
|
+
cv = CASTS[:time].call("08:47:23")
|
33
|
+
cv.should == Time.parse("08:47:23")
|
34
|
+
cv.class.should == Time
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe DimensionSegmentModel do
|
40
|
+
def create(attrs={})
|
41
|
+
dimension_model = Object.new
|
42
|
+
stub(dimension_model).key{:foodim}
|
43
|
+
DimensionSegmentModel.new({ :key=>:foo,
|
44
|
+
:dimension_model=>dimension_model,
|
45
|
+
:fixed_dimension_value=>:foofoo}.merge(attrs))
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should assign attributes on initialization" do
|
49
|
+
dimension_model = Object.new
|
50
|
+
key = Object.new
|
51
|
+
fixed_dimension_value = Object.new
|
52
|
+
extract_dimension_query = Object.new
|
53
|
+
narrow_proc = Object.new
|
54
|
+
values_proc = Object.new
|
55
|
+
label_proc = Object.new
|
56
|
+
value_cast = Object.new
|
57
|
+
measure_modifiers = Object.new
|
58
|
+
|
59
|
+
dsm = DimensionSegmentModel.new(:dimension_model=>dimension_model,
|
60
|
+
:key=>key,
|
61
|
+
:fixed_dimension_value=>fixed_dimension_value,
|
62
|
+
:narrow_proc=>narrow_proc,
|
63
|
+
:values_proc=>values_proc,
|
64
|
+
:label_proc=>label_proc,
|
65
|
+
:value_cast=>value_cast,
|
66
|
+
:measure_modifiers=>measure_modifiers)
|
67
|
+
dsm.dimension_model.should == dimension_model
|
68
|
+
dsm.key.should == key
|
69
|
+
dsm.fixed_dimension_value.should == fixed_dimension_value
|
70
|
+
dsm.narrow_proc.should == narrow_proc
|
71
|
+
dsm.values_proc.should == values_proc
|
72
|
+
dsm.label_proc.should == label_proc
|
73
|
+
dsm.value_cast.should == value_cast
|
74
|
+
dsm.measure_modifiers.should == measure_modifiers
|
75
|
+
|
76
|
+
dsm = DimensionSegmentModel.new(:dimension_model=>dimension_model,
|
77
|
+
:key=>key,
|
78
|
+
:extract_dimension_query=>extract_dimension_query,
|
79
|
+
:narrow_proc=>narrow_proc,
|
80
|
+
:values_proc=>values_proc,
|
81
|
+
:label_proc=>label_proc,
|
82
|
+
:value_cast=>value_cast,
|
83
|
+
:measure_modifiers=>measure_modifiers)
|
84
|
+
dsm.dimension_model.should == dimension_model
|
85
|
+
dsm.key.should == key
|
86
|
+
dsm.extract_dimension_query.should == extract_dimension_query
|
87
|
+
dsm.narrow_proc.should == narrow_proc
|
88
|
+
dsm.values_proc.should == values_proc
|
89
|
+
dsm.label_proc.should == label_proc
|
90
|
+
dsm.value_cast.should == value_cast
|
91
|
+
dsm.measure_modifiers.should == measure_modifiers
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "do_narrow" do
|
95
|
+
it "should narrow the scope with the narrow_proc" do
|
96
|
+
narrow_proc = Object.new
|
97
|
+
dsm = create(:narrow_proc=>narrow_proc)
|
98
|
+
|
99
|
+
scope = Object.new
|
100
|
+
narrowed_scope = Object.new
|
101
|
+
mock(narrow_proc).call(scope){narrowed_scope}
|
102
|
+
|
103
|
+
dsm.do_narrow(scope).should == narrowed_scope
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return the scope unchaged if no narrow_proc" do
|
107
|
+
dsm = create
|
108
|
+
scope = Object.new
|
109
|
+
dsm.do_narrow(scope).should == scope
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "do_cast" do
|
114
|
+
it "should cast the value with the referenced Proc if value_cast is given" do
|
115
|
+
dsm = create(:value_cast=>:int)
|
116
|
+
dsm.do_cast("100").should == 100
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should return the value unchanged if no value_cast is given" do
|
120
|
+
dsm = create
|
121
|
+
dsm.do_cast("100").should == "100"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "do_modify" do
|
126
|
+
it "should modify the measure_def with the modifier_proc" do
|
127
|
+
dsm = create(:measure_modifiers => {:foo=>Proc.new{|mdef| "#{mdef}/12"}})
|
128
|
+
dsm.do_modify(:foo, "count(*)").should == "count(*)/12"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return the measure_def unchanged if no modifier_proc is given" do
|
132
|
+
dsm = create
|
133
|
+
dsm.do_modify(:foo, "count(*)").should == "count(*)"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "select_string" do
|
138
|
+
it "should return a quoted aliased fixed_dimension_value if given" do
|
139
|
+
mock(ActiveRecord::Base).quote_value(:foofoo){"foofoo"}
|
140
|
+
dsm = create
|
141
|
+
dsm.select_string.should == "foofoo as foodim"
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should return an aliased version of the extract_dimension_query if given" do
|
145
|
+
dsm = create(:fixed_dimension_value=>nil, :extract_dimension_query=>"foocol")
|
146
|
+
dsm.select_string.should == "foocol as foodim"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "group_by_column" do
|
151
|
+
it "should return the stringified dimension key" do
|
152
|
+
dsm = create
|
153
|
+
dsm.group_by_column.should == "foodim"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "get_values" do
|
158
|
+
it "should return a stringified fixed_dimension_value if given" do
|
159
|
+
dsm = create
|
160
|
+
dsm.get_values(Object.new).should == ["foofoo"]
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should narrow the scope and return distinct values if extract_dimension_query" do
|
164
|
+
dsm = create(:fixed_dimension_value=>nil, :extract_dimension_query=>"foocol")
|
165
|
+
|
166
|
+
r1 = Object.new
|
167
|
+
mock(r1).foodim{10}
|
168
|
+
r2 = Object.new
|
169
|
+
mock(r2).foodim{20}
|
170
|
+
|
171
|
+
scope = Object.new
|
172
|
+
mock(scope).select("distinct foocol as foodim").mock!.all{[r1,r2]}
|
173
|
+
|
174
|
+
dsm.get_values(scope).should == [10,20]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "labels" do
|
179
|
+
it "should return capitalized stringified keys if no label_proc is given" do
|
180
|
+
dsm = create
|
181
|
+
dsm.labels([:foo, :foo_bar, "foo_bar_baz"]).should == {:foo=>"Foo", :foo_bar=>"Foo Bar", "foo_bar_baz"=>"Foo Bar Baz"}
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should call label_proc for each value if label_proc is given" do
|
185
|
+
dsm = create(:label_proc=>lambda{|v| v.to_s.upcase})
|
186
|
+
dsm.labels([:foo]).should == {:foo=>"FOO"}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe DimensionModel do
|
192
|
+
describe "index_list" do
|
193
|
+
it "should return a list of lists each with a segment_model index when given a nil prefix" do
|
194
|
+
dm = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new])
|
195
|
+
dm.index_list(nil).should == [[0],[1]]
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should suffix each segment_model index to each prefix when given a non-nil prefix" do
|
199
|
+
dm = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new])
|
200
|
+
dm.index_list([[0],[1]]).should == [[0,0],[1,0],[0,1],[1,1]]
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe MeasureModel do
|
206
|
+
describe "select_string" do
|
207
|
+
it "should return an aliased definition if no region_segment_models modify the definition" do
|
208
|
+
mm = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
209
|
+
|
210
|
+
sm1 = Object.new
|
211
|
+
mock(sm1).do_modify(:count, "count(*)"){"count(*)"}
|
212
|
+
sm2 = Object.new
|
213
|
+
mock(sm2).do_modify(:count, "count(*)"){"count(*)"}
|
214
|
+
|
215
|
+
mm.select_string([sm1, sm2]).should == "count(*) as count"
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should allow the region_segment_models to modify the definition" do
|
219
|
+
mm = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
220
|
+
|
221
|
+
sm1 = Object.new
|
222
|
+
mock(sm1).do_modify(:count, anything){|key,mdef| "#{mdef}/12"}
|
223
|
+
sm2 = Object.new
|
224
|
+
mock(sm2).do_modify(:count, anything){|key,mdef| mdef}
|
225
|
+
|
226
|
+
mm.select_string([sm1, sm2]).should == "count(*)/12 as count"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "do_cast" do
|
231
|
+
it "should return the value unchanged if no cast is specified" do
|
232
|
+
mm = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
233
|
+
mm.do_cast("100").should == "100"
|
234
|
+
mm.do_cast("100").class.should == "100".class
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should cast the value according to the cast specified" do
|
238
|
+
mm = MeasureModel.new(:key=>:count, :definition=>"count(*)", :cast=>:int)
|
239
|
+
mm.do_cast("100").should == 100
|
240
|
+
mm.do_cast("100").class.should == 100.class
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe DatasetModel do
|
246
|
+
describe "region_segment_model_indexes" do
|
247
|
+
|
248
|
+
it "should produce the cross-producton of dimension segment indexes for one dimension" do
|
249
|
+
dim1 = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new])
|
250
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
251
|
+
|
252
|
+
dm = DatasetModel.new(:source=>Object.new,
|
253
|
+
:dimension_models=>[dim1],
|
254
|
+
:measure_models=>[mm1])
|
255
|
+
|
256
|
+
dm.region_segment_model_indexes.to_set.should == [[0],[1]].to_set
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should produce the cross-product of dimension segment indexes for two dimensions" do
|
260
|
+
dim1 = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new])
|
261
|
+
dim2 = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new, Object.new])
|
262
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
263
|
+
|
264
|
+
dm = DatasetModel.new(:source=>Object.new,
|
265
|
+
:dimension_models=>[dim1, dim2],
|
266
|
+
:measure_models=>[mm1])
|
267
|
+
|
268
|
+
dm.region_segment_model_indexes.to_set.should == [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2]].to_set
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should produce the cross-product of dimension segment indexes for 3 dimensions" do
|
272
|
+
dim1 = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new])
|
273
|
+
dim2 = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new, Object.new])
|
274
|
+
dim3 = DimensionModel.new(:key=>:foo, :segment_models=>[Object.new, Object.new])
|
275
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
276
|
+
|
277
|
+
dm = DatasetModel.new(:source=>Object.new,
|
278
|
+
:dimension_models=>[dim1, dim2, dim3],
|
279
|
+
:measure_models=>[mm1])
|
280
|
+
|
281
|
+
dm.region_segment_model_indexes.to_set.should == [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[0,2,0],[0,2,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1],[1,2,0],[1,2,1]].to_set
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "all_dimension_segment_models" do
|
286
|
+
it "should return a list lists of dimension segments" do
|
287
|
+
dim1sm1 = Object.new
|
288
|
+
dim1sm2 = Object.new
|
289
|
+
dim1 = DimensionModel.new(:key=>:foo, :segment_models=>[dim1sm1, dim1sm2])
|
290
|
+
dim2sm1 = Object.new
|
291
|
+
dim2sm2 = Object.new
|
292
|
+
dim2sm3 = Object.new
|
293
|
+
dim2 = DimensionModel.new(:key=>:foo, :segment_models=>[dim2sm1, dim2sm2, dim2sm3])
|
294
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
295
|
+
|
296
|
+
dm = DatasetModel.new(:source=>Object.new,
|
297
|
+
:dimension_models=>[dim1, dim2],
|
298
|
+
:measure_models=>[mm1])
|
299
|
+
dm.all_dimension_segment_models.should == [[dim1sm1, dim1sm2], [dim2sm1, dim2sm2, dim2sm3]]
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
describe "region_segment_models" do
|
304
|
+
it "should produce a list of dimension segment models corresponding to the supplied indexes" do
|
305
|
+
dim0sm0 = Object.new
|
306
|
+
dim0sm1 = Object.new
|
307
|
+
dim0 = DimensionModel.new(:key=>:foo, :segment_models=>[dim0sm0, dim0sm1])
|
308
|
+
dim1sm0 = Object.new
|
309
|
+
dim1sm1 = Object.new
|
310
|
+
dim1sm2 = Object.new
|
311
|
+
dim1 = DimensionModel.new(:key=>:foo, :segment_models=>[dim1sm0, dim1sm1, dim1sm2])
|
312
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
313
|
+
|
314
|
+
dm = DatasetModel.new(:source=>Object.new,
|
315
|
+
:dimension_models=>[dim0, dim1],
|
316
|
+
:measure_models=>[mm1])
|
317
|
+
dm.region_segment_models([0,1]).should == [dim0sm0, dim1sm1]
|
318
|
+
dm.region_segment_models([1,2]).should == [dim0sm1, dim1sm2]
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "with_regions" do
|
323
|
+
it "should iterate of all regions calling the proc with the region segment models" do
|
324
|
+
dim0sm0 = Object.new
|
325
|
+
dim0sm1 = Object.new
|
326
|
+
dim0 = DimensionModel.new(:key=>:foo, :segment_models=>[dim0sm0, dim0sm1])
|
327
|
+
dim1sm0 = Object.new
|
328
|
+
dim1sm1 = Object.new
|
329
|
+
dim1sm2 = Object.new
|
330
|
+
dim1 = DimensionModel.new(:key=>:foo, :segment_models=>[dim1sm0, dim1sm1, dim1sm2])
|
331
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
332
|
+
|
333
|
+
dm = DatasetModel.new(:source=>Object.new,
|
334
|
+
:dimension_models=>[dim0, dim1],
|
335
|
+
:measure_models=>[mm1])
|
336
|
+
|
337
|
+
all_region_segment_models = [[dim0sm0,dim1sm0],[dim0sm0,dim1sm1],[dim0sm0,dim1sm2],[dim0sm1,dim1sm0],[dim0sm1,dim1sm1],[dim0sm1,dim1sm2]].to_set
|
338
|
+
dm.with_regions do |region_segment_models|
|
339
|
+
all_region_segment_models.delete(region_segment_models)
|
340
|
+
end
|
341
|
+
all_region_segment_models.empty?.should == true
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
describe "construct_query" do
|
346
|
+
it "should narrow the scope according to each segment in the region, select dimension and measure values, and group by dimensions" do
|
347
|
+
dim0sm0 = Object.new
|
348
|
+
dim0 = DimensionModel.new(:key=>:foo, :segment_models=>[dim0sm0])
|
349
|
+
dim1sm0 = Object.new
|
350
|
+
dim1 = DimensionModel.new(:key=>:bar, :segment_models=>[dim1sm0])
|
351
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)")
|
352
|
+
|
353
|
+
dm = DatasetModel.new(:source=>Object.new,
|
354
|
+
:dimension_models=>[dim0, dim1],
|
355
|
+
:measure_models=>[mm1])
|
356
|
+
|
357
|
+
scope = Object.new
|
358
|
+
region_segment_models = [dim0sm0, dim1sm0]
|
359
|
+
measure_models = [mm1]
|
360
|
+
|
361
|
+
# the narrowing
|
362
|
+
scope_n1 = Object.new
|
363
|
+
mock(dim0sm0).do_narrow(scope){scope_n1}
|
364
|
+
scope_n2 = Object.new
|
365
|
+
mock(dim1sm0).do_narrow(scope_n1){scope_n2}
|
366
|
+
|
367
|
+
# dimension_select_strings
|
368
|
+
mock(dim0sm0).select_string{"foofoo as foo"}
|
369
|
+
mock(dim1sm0).select_string{"barbar as bar"}
|
370
|
+
|
371
|
+
|
372
|
+
# measure_select_strings
|
373
|
+
mock(mm1).select_string([dim0sm0, dim1sm0]){"count(*) as count"}
|
374
|
+
|
375
|
+
select_string = "foofoo as foo,barbar as bar,count(*) as count"
|
376
|
+
|
377
|
+
# group_string
|
378
|
+
mock(dim0sm0).group_by_column{"foo"}
|
379
|
+
mock(dim1sm0).group_by_column{"bar"}
|
380
|
+
group_string = "foo,bar"
|
381
|
+
|
382
|
+
scope_n3 = Object.new
|
383
|
+
query = Object.new
|
384
|
+
mock(scope_n2).select(select_string){scope_n3}.mock!.group(group_string){query}
|
385
|
+
|
386
|
+
dm.construct_query(scope, region_segment_models, measure_models).should == query
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
describe "extract" do
|
391
|
+
it "should extract row records into hashes keyed by dimension-values and measure-keys" do
|
392
|
+
dim0sm0 = Object.new
|
393
|
+
dim0 = DimensionModel.new(:key=>:foo, :segment_models=>[dim0sm0])
|
394
|
+
dim1sm0 = Object.new
|
395
|
+
dim1 = DimensionModel.new(:key=>:bar, :segment_models=>[dim1sm0])
|
396
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)", :cast=>:int)
|
397
|
+
|
398
|
+
dm = DatasetModel.new(:source=>Object.new,
|
399
|
+
:dimension_models=>[dim0, dim1],
|
400
|
+
:measure_models=>[mm1])
|
401
|
+
|
402
|
+
stub(dim0sm0).dimension_model{dim0}
|
403
|
+
stub(dim0sm0).do_cast(anything){|value| value}
|
404
|
+
stub(dim1sm0).dimension_model{dim1}
|
405
|
+
stub(dim1sm0).do_cast(anything){|value| value}
|
406
|
+
|
407
|
+
# ActiveRecord methods are called on row instances
|
408
|
+
row1 = Object.new
|
409
|
+
mock(row1).foo{"foo1"}
|
410
|
+
mock(row1).bar{"bar1"}
|
411
|
+
mock(row1).count{"10"}
|
412
|
+
row2 = Object.new
|
413
|
+
mock(row2).foo{"foo2"}
|
414
|
+
mock(row2).bar{"bar2"}
|
415
|
+
mock(row2).count{"20"}
|
416
|
+
|
417
|
+
dm.extract([row1,row2], [dim0sm0, dim1sm0], [mm1]).should == [{:foo=>"foo1", :bar=>"bar1", :count=>10},
|
418
|
+
{:foo=>"foo2", :bar=>"bar2", :count=>20}]
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
|
423
|
+
describe "do_queries" do
|
424
|
+
it "should do a query for each region and put the results in a dataset" do
|
425
|
+
dim0sm0 = Object.new
|
426
|
+
dim0 = DimensionModel.new(:key=>:foo, :segment_models=>[dim0sm0])
|
427
|
+
dim1sm0 = Object.new
|
428
|
+
dim1 = DimensionModel.new(:key=>:bar, :segment_models=>[dim1sm0])
|
429
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)", :cast=>:int)
|
430
|
+
|
431
|
+
dm = DatasetModel.new(:source=>Object.new,
|
432
|
+
:dimension_models=>[dim0, dim1],
|
433
|
+
:measure_models=>[mm1])
|
434
|
+
|
435
|
+
mock(dm).with_regions do |proc|
|
436
|
+
proc.call([dim0sm0,dim1sm0])
|
437
|
+
end
|
438
|
+
|
439
|
+
query = Object.new
|
440
|
+
mock(dm).construct_query(dm.source, [dim0sm0, dim1sm0], [mm1]){query}
|
441
|
+
records = Object.new
|
442
|
+
mock(query).all{records}
|
443
|
+
mock(dm).extract(records, [dim0sm0, dim1sm0], [mm1]){[{:foo=>"foo1", :bar=>"bar1", :count=>10},
|
444
|
+
{:foo=>"foo2", :bar=>"bar2", :count=>20}]}
|
445
|
+
|
446
|
+
data = dm.do_queries
|
447
|
+
data.should == [{:foo=>"foo1", :bar=>"bar1", :count=>10},
|
448
|
+
{:foo=>"foo2", :bar=>"bar2", :count=>20}]
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
describe "collect" do
|
453
|
+
it "should do_queries and use the result to constract a Dataset" do
|
454
|
+
dim0sm0 = Object.new
|
455
|
+
dim0 = DimensionModel.new(:key=>:foo, :segment_models=>[dim0sm0])
|
456
|
+
mm1 = MeasureModel.new(:key=>:count, :definition=>"count(*)", :cast=>:int)
|
457
|
+
|
458
|
+
dm = DatasetModel.new(:source=>Object.new,
|
459
|
+
:dimension_models=>[dim0],
|
460
|
+
:measure_models => [mm1])
|
461
|
+
|
462
|
+
dataset = Object.new
|
463
|
+
mock(dm).do_queries{dataset}
|
464
|
+
|
465
|
+
mock(MDQuery::Dataset::Dataset).new(dm, dataset)
|
466
|
+
|
467
|
+
dm.collect
|
468
|
+
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|