mondrian-olap 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +15 -0
  3. data/LICENSE-Mondrian.html +259 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.rdoc +219 -0
  6. data/RUNNING_TESTS.rdoc +41 -0
  7. data/Rakefile +46 -0
  8. data/VERSION +1 -0
  9. data/lib/mondrian-olap.rb +1 -0
  10. data/lib/mondrian/jars/commons-collections-3.1.jar +0 -0
  11. data/lib/mondrian/jars/commons-dbcp-1.2.1.jar +0 -0
  12. data/lib/mondrian/jars/commons-logging-1.0.4.jar +0 -0
  13. data/lib/mondrian/jars/commons-math-1.0.jar +0 -0
  14. data/lib/mondrian/jars/commons-pool-1.2.jar +0 -0
  15. data/lib/mondrian/jars/commons-vfs-1.0.jar +0 -0
  16. data/lib/mondrian/jars/eigenbase-properties.jar +0 -0
  17. data/lib/mondrian/jars/eigenbase-resgen.jar +0 -0
  18. data/lib/mondrian/jars/eigenbase-xom.jar +0 -0
  19. data/lib/mondrian/jars/javacup.jar +0 -0
  20. data/lib/mondrian/jars/log4j-1.2.8.jar +0 -0
  21. data/lib/mondrian/jars/log4j.properties +18 -0
  22. data/lib/mondrian/jars/mondrian.jar +0 -0
  23. data/lib/mondrian/jars/olap4j.jar +0 -0
  24. data/lib/mondrian/olap.rb +14 -0
  25. data/lib/mondrian/olap/connection.rb +122 -0
  26. data/lib/mondrian/olap/cube.rb +236 -0
  27. data/lib/mondrian/olap/query.rb +313 -0
  28. data/lib/mondrian/olap/result.rb +155 -0
  29. data/lib/mondrian/olap/schema.rb +158 -0
  30. data/lib/mondrian/olap/schema_element.rb +123 -0
  31. data/mondrian-olap.gemspec +116 -0
  32. data/spec/connection_spec.rb +56 -0
  33. data/spec/cube_spec.rb +259 -0
  34. data/spec/fixtures/MondrianTest.xml +128 -0
  35. data/spec/fixtures/MondrianTestOracle.xml +128 -0
  36. data/spec/query_spec.rb +582 -0
  37. data/spec/rake_tasks.rb +185 -0
  38. data/spec/schema_definition_spec.rb +345 -0
  39. data/spec/spec_helper.rb +67 -0
  40. data/spec/support/matchers/be_like.rb +24 -0
  41. metadata +217 -0
@@ -0,0 +1,185 @@
1
+ namespace :db do
2
+ task :require_spec_helper do
3
+ require File.expand_path("../spec_helper", __FILE__)
4
+ end
5
+
6
+ desc "Create test database tables"
7
+ task :create_tables => :require_spec_helper do
8
+ puts "==> Creating tables for test data"
9
+ ActiveRecord::Schema.define do
10
+
11
+ create_table :time, :force => true do |t|
12
+ t.datetime :the_date
13
+ t.string :the_day, :limit => 30
14
+ t.string :the_month, :limit => 30
15
+ t.integer :the_year
16
+ t.integer :day_of_month
17
+ t.integer :week_of_year
18
+ t.integer :month_of_year
19
+ t.string :quarter, :limit => 30
20
+ end
21
+
22
+ create_table :products, :force => true do |t|
23
+ t.integer :product_class_id
24
+ t.string :brand_name, :limit => 60
25
+ t.string :product_name, :limit => 60
26
+ end
27
+
28
+ create_table :product_classes, :force => true do |t|
29
+ t.string :product_subcategory, :limit => 30
30
+ t.string :product_category, :limit => 30
31
+ t.string :product_department, :limit => 30
32
+ t.string :product_family, :limit => 30
33
+ end
34
+
35
+ create_table :customers, :force => true do |t|
36
+ t.string :country, :limit => 30
37
+ t.string :state_province, :limit => 30
38
+ t.string :city, :limit => 30
39
+ t.string :fname, :limit => 30
40
+ t.string :lname, :limit => 30
41
+ t.string :fullname, :limit => 60
42
+ t.string :gender, :limit => 30
43
+ end
44
+
45
+ create_table :sales, :force => true, :id => false do |t|
46
+ t.integer :product_id
47
+ t.integer :time_id
48
+ t.integer :customer_id
49
+ t.decimal :store_sales, :precision => 10, :scale => 4
50
+ t.decimal :store_cost, :precision => 10, :scale => 4
51
+ t.decimal :unit_sales, :precision => 10, :scale => 4
52
+ end
53
+ end
54
+ end
55
+
56
+ task :define_models => :require_spec_helper do
57
+ class TimeDimension < ActiveRecord::Base
58
+ set_table_name "time"
59
+ validates_presence_of :the_date
60
+ before_create do
61
+ self.the_day = the_date.strftime("%A")
62
+ self.the_month = the_date.strftime("%B")
63
+ self.the_year = the_date.strftime("%Y").to_i
64
+ self.day_of_month = the_date.strftime("%d").to_i
65
+ self.week_of_year = the_date.strftime("%W").to_i
66
+ self.month_of_year = the_date.strftime("%m").to_i
67
+ self.quarter = "Q#{(month_of_year-1)/3+1}"
68
+ end
69
+ end
70
+ class Product < ActiveRecord::Base
71
+ belongs_to :product_class
72
+ end
73
+ class ProductClass < ActiveRecord::Base
74
+ end
75
+ class Customer < ActiveRecord::Base
76
+ end
77
+ class Sales < ActiveRecord::Base
78
+ set_table_name "sales"
79
+ belongs_to :time_by_day
80
+ belongs_to :product
81
+ belongs_to :customer
82
+ end
83
+ end
84
+
85
+ desc "Create test data"
86
+ task :create_data => [:create_tables, :create_time_data, :create_product_data, :create_customer_data, :create_sales_data]
87
+
88
+ task :create_time_data => :define_models do
89
+ puts "==> Creating time dimension"
90
+ TimeDimension.delete_all
91
+ start_time = Time.local(2010,1,1)
92
+ (2*365).times do |i|
93
+ TimeDimension.create!(:the_date => start_time + i.day)
94
+ end
95
+ end
96
+
97
+ task :create_product_data => :define_models do
98
+ puts "==> Creating product data"
99
+ Product.delete_all
100
+ ProductClass.delete_all
101
+ families = ["Drink", "Food", "Non-Consumable"]
102
+ (1..100).each do |i|
103
+ product_class = ProductClass.create!(
104
+ :product_family => families[i % 3],
105
+ :product_department => "Department #{i}",
106
+ :product_category => "Category #{i}",
107
+ :product_subcategory => "Subcategory #{i}"
108
+ )
109
+ Product.create!(
110
+ :product_class_id => product_class.id,
111
+ :brand_name => "Brand #{i}",
112
+ :product_name => "Product #{i}"
113
+ )
114
+ end
115
+ end
116
+
117
+ task :create_customer_data => :define_models do
118
+ puts "==> Creating customer data"
119
+ Customer.delete_all
120
+ i = 0
121
+ [
122
+ ["Canada", "BC", "Burnaby"],["Canada", "BC", "Cliffside"],["Canada", "BC", "Haney"],["Canada", "BC", "Ladner"],
123
+ ["Canada", "BC", "Langford"],["Canada", "BC", "Langley"],["Canada", "BC", "Metchosin"],["Canada", "BC", "N. Vancouver"],
124
+ ["Canada", "BC", "Newton"],["Canada", "BC", "Oak Bay"],["Canada", "BC", "Port Hammond"],["Canada", "BC", "Richmond"],
125
+ ["Canada", "BC", "Royal Oak"],["Canada", "BC", "Shawnee"],["Canada", "BC", "Sooke"],["Canada", "BC", "Vancouver"],
126
+ ["Canada", "BC", "Victoria"],["Canada", "BC", "Westminster"],
127
+ ["Mexico", "DF", "San Andres"],["Mexico", "DF", "Santa Anita"],["Mexico", "DF", "Santa Fe"],["Mexico", "DF", "Tixapan"],
128
+ ["Mexico", "Guerrero", "Acapulco"],["Mexico", "Jalisco", "Guadalajara"],["Mexico", "Mexico", "Mexico City"],
129
+ ["Mexico", "Oaxaca", "Tlaxiaco"],["Mexico", "Sinaloa", "La Cruz"],["Mexico", "Veracruz", "Orizaba"],
130
+ ["Mexico", "Yucatan", "Merida"],["Mexico", "Zacatecas", "Camacho"],["Mexico", "Zacatecas", "Hidalgo"],
131
+ ["USA", "CA", "Altadena"],["USA", "CA", "Arcadia"],["USA", "CA", "Bellflower"],["USA", "CA", "Berkeley"],
132
+ ["USA", "CA", "Beverly Hills"],["USA", "CA", "Burbank"],["USA", "CA", "Burlingame"],["USA", "CA", "Chula Vista"],
133
+ ["USA", "CA", "Colma"],["USA", "CA", "Concord"],["USA", "CA", "Coronado"],["USA", "CA", "Daly City"],
134
+ ["USA", "CA", "Downey"],["USA", "CA", "El Cajon"],["USA", "CA", "Fremont"],["USA", "CA", "Glendale"],
135
+ ["USA", "CA", "Grossmont"],["USA", "CA", "Imperial Beach"],["USA", "CA", "La Jolla"],["USA", "CA", "La Mesa"],
136
+ ["USA", "CA", "Lakewood"],["USA", "CA", "Lemon Grove"],["USA", "CA", "Lincoln Acres"],["USA", "CA", "Long Beach"],
137
+ ["USA", "CA", "Los Angeles"],["USA", "CA", "Mill Valley"],["USA", "CA", "National City"],["USA", "CA", "Newport Beach"],
138
+ ["USA", "CA", "Novato"],["USA", "CA", "Oakland"],["USA", "CA", "Palo Alto"],["USA", "CA", "Pomona"],
139
+ ["USA", "CA", "Redwood City"],["USA", "CA", "Richmond"],["USA", "CA", "San Carlos"],["USA", "CA", "San Diego"],
140
+ ["USA", "CA", "San Francisco"],["USA", "CA", "San Gabriel"],["USA", "CA", "San Jose"],["USA", "CA", "Santa Cruz"],
141
+ ["USA", "CA", "Santa Monica"],["USA", "CA", "Spring Valley"],["USA", "CA", "Torrance"],["USA", "CA", "West Covina"],
142
+ ["USA", "CA", "Woodland Hills"],
143
+ ["USA", "OR", "Albany"],["USA", "OR", "Beaverton"],["USA", "OR", "Corvallis"],["USA", "OR", "Lake Oswego"],
144
+ ["USA", "OR", "Lebanon"],["USA", "OR", "Milwaukie"],["USA", "OR", "Oregon City"],["USA", "OR", "Portland"],
145
+ ["USA", "OR", "Salem"],["USA", "OR", "W. Linn"],["USA", "OR", "Woodburn"],
146
+ ["USA", "WA", "Anacortes"],["USA", "WA", "Ballard"],["USA", "WA", "Bellingham"],["USA", "WA", "Bremerton"],
147
+ ["USA", "WA", "Burien"],["USA", "WA", "Edmonds"],["USA", "WA", "Everett"],["USA", "WA", "Issaquah"],
148
+ ["USA", "WA", "Kirkland"],["USA", "WA", "Lynnwood"],["USA", "WA", "Marysville"],["USA", "WA", "Olympia"],
149
+ ["USA", "WA", "Port Orchard"],["USA", "WA", "Puyallup"],["USA", "WA", "Redmond"],["USA", "WA", "Renton"],
150
+ ["USA", "WA", "Seattle"],["USA", "WA", "Sedro Woolley"],["USA", "WA", "Spokane"],["USA", "WA", "Tacoma"],
151
+ ["USA", "WA", "Walla Walla"],["USA", "WA", "Yakima"]
152
+ ].each do |country, state, city|
153
+ i += 1
154
+ Customer.create!(
155
+ :country => country,
156
+ :state_province => state,
157
+ :city => city,
158
+ :fname => "First#{i}",
159
+ :lname => "Last#{i}",
160
+ :fullname => "First#{i} Last#{i}",
161
+ :gender => i % 2 == 0 ? "M" : "F"
162
+ )
163
+ end
164
+ end
165
+
166
+ task :create_sales_data => :define_models do
167
+ puts "==> Creating sales data"
168
+ Sales.delete_all
169
+ count = 100
170
+ products = Product.order("id").limit(count).all
171
+ times = TimeDimension.order("id").limit(count).all
172
+ customers = Customer.order("id").limit(count).all
173
+ count.times do |i|
174
+ Sales.create!(
175
+ :product_id => products[i].id,
176
+ :time_id => times[i].id,
177
+ :customer_id => customers[i].id,
178
+ :store_sales => BigDecimal("2#{i}.12"),
179
+ :store_cost => BigDecimal("1#{i}.1234"),
180
+ :unit_sales => i+1
181
+ )
182
+ end
183
+ end
184
+
185
+ end
@@ -0,0 +1,345 @@
1
+ require "spec_helper"
2
+
3
+ describe "Schema definition" do
4
+
5
+ describe "elements" do
6
+ before(:each) do
7
+ @schema = Mondrian::OLAP::Schema.new
8
+ end
9
+
10
+ describe "root element" do
11
+ it "should render to XML" do
12
+ @schema.to_xml.should be_like <<-XML
13
+ <?xml version="1.0"?>
14
+ <Schema/>
15
+ XML
16
+ end
17
+
18
+ it "should render to XML with attributes" do
19
+ @schema.define('FoodMart') do
20
+ description 'Demo "FoodMart" schema'
21
+ end
22
+ @schema.to_xml.should be_like <<-XML
23
+ <?xml version="1.0"?>
24
+ <Schema description="Demo &quot;FoodMart&quot; schema" name="FoodMart"/>
25
+ XML
26
+ end
27
+
28
+ it "should render to XML using class method" do
29
+ schema = Mondrian::OLAP::Schema.define('FoodMart')
30
+ schema.to_xml.should be_like <<-XML
31
+ <?xml version="1.0"?>
32
+ <Schema name="FoodMart"/>
33
+ XML
34
+ end
35
+ end
36
+
37
+ describe "Cube" do
38
+ it "should render to XML" do
39
+ @schema.define do
40
+ cube 'Sales' do
41
+ default_measure 'Unit Sales'
42
+ description 'Sales cube'
43
+ cache false
44
+ enabled true
45
+ end
46
+ end
47
+ @schema.to_xml.should be_like <<-XML
48
+ <?xml version="1.0"?>
49
+ <Schema name="default">
50
+ <Cube cache="false" defaultMeasure="Unit Sales" description="Sales cube" enabled="true" name="Sales"/>
51
+ </Schema>
52
+ XML
53
+ end
54
+
55
+ it "should render to XML using options hash" do
56
+ @schema.define do
57
+ cube 'Sales', :default_measure => 'Unit Sales',
58
+ :description => 'Sales cube', :cache => false, :enabled => true
59
+ end
60
+ @schema.to_xml.should be_like <<-XML
61
+ <?xml version="1.0"?>
62
+ <Schema name="default">
63
+ <Cube cache="false" defaultMeasure="Unit Sales" description="Sales cube" enabled="true" name="Sales"/>
64
+ </Schema>
65
+ XML
66
+ end
67
+ end
68
+
69
+ describe "Table" do
70
+ it "should render to XML" do
71
+ @schema.define do
72
+ cube 'Sales' do
73
+ table 'sales_fact', :alias => 'sales'
74
+ end
75
+ end
76
+ @schema.to_xml.should be_like <<-XML
77
+ <?xml version="1.0"?>
78
+ <Schema name="default">
79
+ <Cube name="Sales">
80
+ <Table alias="sales" name="sales_fact"/>
81
+ </Cube>
82
+ </Schema>
83
+ XML
84
+ end
85
+
86
+ it "should render table name in uppercase when using Oracle driver" do
87
+ @schema.define do
88
+ cube 'Sales' do
89
+ table 'sales_fact', :alias => 'sales'
90
+ end
91
+ end
92
+ @schema.to_xml(:driver => 'oracle').should be_like <<-XML
93
+ <?xml version="1.0"?>
94
+ <Schema name="default">
95
+ <Cube name="Sales">
96
+ <Table alias="SALES" name="SALES_FACT"/>
97
+ </Cube>
98
+ </Schema>
99
+ XML
100
+ end
101
+ end
102
+
103
+ describe "Dimension" do
104
+ it "should render to XML" do
105
+ @schema.define do
106
+ cube 'Sales' do
107
+ dimension 'Gender' do
108
+ foreign_key 'customer_id'
109
+ hierarchy do
110
+ has_all true
111
+ all_member_name 'All Genders'
112
+ primary_key 'customer_id'
113
+ table 'customer'
114
+ level 'Gender', :column => 'gender', :unique_members => true
115
+ end
116
+ end
117
+ end
118
+ end
119
+ @schema.to_xml.should be_like <<-XML
120
+ <?xml version="1.0"?>
121
+ <Schema name="default">
122
+ <Cube name="Sales">
123
+ <Dimension foreignKey="customer_id" name="Gender">
124
+ <Hierarchy allMemberName="All Genders" hasAll="true" primaryKey="customer_id">
125
+ <Table name="customer"/>
126
+ <Level column="gender" name="Gender" uniqueMembers="true"/>
127
+ </Hierarchy>
128
+ </Dimension>
129
+ </Cube>
130
+ </Schema>
131
+ XML
132
+ end
133
+
134
+ it "should render time dimension" do
135
+ @schema.define do
136
+ cube 'Sales' do
137
+ dimension 'Time' do
138
+ foreign_key 'time_id'
139
+ hierarchy do
140
+ has_all false
141
+ primary_key 'time_id'
142
+ table 'time_by_day'
143
+ level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true
144
+ level 'Quarter', :column => 'quarter', :unique_members => false
145
+ level 'Month', :column => 'month_of_year', :type => 'Numeric', :unique_members => false
146
+ end
147
+ end
148
+ end
149
+ end
150
+ @schema.to_xml.should be_like <<-XML
151
+ <?xml version="1.0"?>
152
+ <Schema name="default">
153
+ <Cube name="Sales">
154
+ <Dimension foreignKey="time_id" name="Time">
155
+ <Hierarchy hasAll="false" primaryKey="time_id">
156
+ <Table name="time_by_day"/>
157
+ <Level column="the_year" name="Year" type="Numeric" uniqueMembers="true"/>
158
+ <Level column="quarter" name="Quarter" uniqueMembers="false"/>
159
+ <Level column="month_of_year" name="Month" type="Numeric" uniqueMembers="false"/>
160
+ </Hierarchy>
161
+ </Dimension>
162
+ </Cube>
163
+ </Schema>
164
+ XML
165
+ end
166
+
167
+ it "should render dimension hierarchy with join" do
168
+ @schema.define do
169
+ cube 'Sales' do
170
+ dimension 'Products', :foreign_key => 'product_id' do
171
+ hierarchy :has_all => true, :all_member_name => 'All Products',
172
+ :primary_key => 'product_id', :primary_key_table => 'product' do
173
+ join :left_key => 'product_class_id', :right_key => 'product_class_id' do
174
+ table 'product'
175
+ table 'product_class'
176
+ end
177
+ level 'Product Family', :table => 'product_class', :column => 'product_family', :unique_members => true
178
+ level 'Brand Name', :table => 'product', :column => 'brand_name', :unique_members => false
179
+ level 'Product Name', :table => 'product', :column => 'product_name', :unique_members => true
180
+ end
181
+ end
182
+ end
183
+ end
184
+ @schema.to_xml.should be_like <<-XML
185
+ <?xml version="1.0"?>
186
+ <Schema name="default">
187
+ <Cube name="Sales">
188
+ <Dimension foreignKey="product_id" name="Products">
189
+ <Hierarchy allMemberName="All Products" hasAll="true" primaryKey="product_id" primaryKeyTable="product">
190
+ <Join leftKey="product_class_id" rightKey="product_class_id">
191
+ <Table name="product"/>
192
+ <Table name="product_class"/>
193
+ </Join>
194
+ <Level column="product_family" name="Product Family" table="product_class" uniqueMembers="true"/>
195
+ <Level column="brand_name" name="Brand Name" table="product" uniqueMembers="false"/>
196
+ <Level column="product_name" name="Product Name" table="product" uniqueMembers="true"/>
197
+ </Hierarchy>
198
+ </Dimension>
199
+ </Cube>
200
+ </Schema>
201
+ XML
202
+ end
203
+
204
+ it "should render table and column names in uppercase when using Oracle driver" do
205
+ @schema.define do
206
+ cube 'Sales' do
207
+ dimension 'Products', :foreign_key => 'product_id' do
208
+ hierarchy :has_all => true, :all_member_name => 'All Products',
209
+ :primary_key => 'product_id', :primary_key_table => 'product' do
210
+ join :left_key => 'product_class_id', :right_key => 'product_class_id' do
211
+ table 'product'
212
+ table 'product_class'
213
+ end
214
+ level 'Product Family', :table => 'product_class', :column => 'product_family', :unique_members => true
215
+ level 'Brand Name', :table => 'product', :column => 'brand_name', :unique_members => false
216
+ level 'Product Name', :table => 'product', :column => 'product_name', :unique_members => true
217
+ end
218
+ end
219
+ end
220
+ end
221
+ @schema.to_xml(:driver => 'oracle').should be_like <<-XML
222
+ <?xml version="1.0"?>
223
+ <Schema name="default">
224
+ <Cube name="Sales">
225
+ <Dimension foreignKey="PRODUCT_ID" name="Products">
226
+ <Hierarchy allMemberName="All Products" hasAll="true" primaryKey="PRODUCT_ID" primaryKeyTable="PRODUCT">
227
+ <Join leftKey="PRODUCT_CLASS_ID" rightKey="PRODUCT_CLASS_ID">
228
+ <Table name="PRODUCT"/>
229
+ <Table name="PRODUCT_CLASS"/>
230
+ </Join>
231
+ <Level column="PRODUCT_FAMILY" name="Product Family" table="PRODUCT_CLASS" uniqueMembers="true"/>
232
+ <Level column="BRAND_NAME" name="Brand Name" table="PRODUCT" uniqueMembers="false"/>
233
+ <Level column="PRODUCT_NAME" name="Product Name" table="PRODUCT" uniqueMembers="true"/>
234
+ </Hierarchy>
235
+ </Dimension>
236
+ </Cube>
237
+ </Schema>
238
+ XML
239
+ end
240
+
241
+ end
242
+
243
+ describe "Measure" do
244
+ it "should render XML" do
245
+ @schema.define do
246
+ cube 'Sales' do
247
+ measure 'Unit Sales' do
248
+ column 'unit_sales'
249
+ aggregator 'sum'
250
+ end
251
+ end
252
+ end
253
+ @schema.to_xml.should be_like <<-XML
254
+ <?xml version="1.0"?>
255
+ <Schema name="default">
256
+ <Cube name="Sales">
257
+ <Measure aggregator="sum" column="unit_sales" name="Unit Sales"/>
258
+ </Cube>
259
+ </Schema>
260
+ XML
261
+ end
262
+
263
+ it "should render column name in uppercase when using Oracle driver" do
264
+ @schema.define do
265
+ cube 'Sales' do
266
+ measure 'Unit Sales' do
267
+ column 'unit_sales'
268
+ aggregator 'sum'
269
+ end
270
+ end
271
+ end
272
+ @schema.to_xml(:driver => 'oracle').should be_like <<-XML
273
+ <?xml version="1.0"?>
274
+ <Schema name="default">
275
+ <Cube name="Sales">
276
+ <Measure aggregator="sum" column="UNIT_SALES" name="Unit Sales"/>
277
+ </Cube>
278
+ </Schema>
279
+ XML
280
+ end
281
+ end
282
+
283
+ describe "Calculated Member" do
284
+ it "should render XML" do
285
+ @schema.define do
286
+ cube 'Sales' do
287
+ calculated_member 'Profit' do
288
+ dimension 'Measures'
289
+ formula '[Measures].[Store Sales] - [Measures].[Store Cost]'
290
+ end
291
+ end
292
+ end
293
+ @schema.to_xml.should be_like <<-XML
294
+ <?xml version="1.0"?>
295
+ <Schema name="default">
296
+ <Cube name="Sales">
297
+ <CalculatedMember dimension="Measures" formula="[Measures].[Store Sales] - [Measures].[Store Cost]" name="Profit"/>
298
+ </Cube>
299
+ </Schema>
300
+ XML
301
+ end
302
+ end
303
+ end
304
+
305
+ describe "connection with schema" do
306
+ before(:all) do
307
+ @schema = Mondrian::OLAP::Schema.define do
308
+ cube 'Sales' do
309
+ table 'sales'
310
+ dimension 'Gender', :foreign_key => 'customer_id' do
311
+ hierarchy :has_all => true, :primary_key => 'id' do
312
+ table 'customers'
313
+ level 'Gender', :column => 'gender', :unique_members => true
314
+ end
315
+ end
316
+ dimension 'Time', :foreign_key => 'time_id' do
317
+ hierarchy :has_all => false, :primary_key => 'id' do
318
+ table 'time'
319
+ level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true
320
+ level 'Quarter', :column => 'quarter', :unique_members => false
321
+ level 'Month', :column => 'month_of_year', :type => 'Numeric', :unique_members => false
322
+ end
323
+ end
324
+ measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum'
325
+ measure 'Store Sales', :column => 'store_sales', :aggregator => 'sum'
326
+ end
327
+ end
328
+ @olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
329
+ end
330
+
331
+ it "should connect" do
332
+ @olap.should be_connected
333
+ end
334
+
335
+ it "should execute query" do
336
+ @olap.from('Sales').
337
+ columns('[Measures].[Unit Sales]', '[Measures].[Store Sales]').
338
+ rows('descendants([Time].[2010].[Q1])').
339
+ where('[Gender].[F]').
340
+ execute.should be_a(Mondrian::OLAP::Result)
341
+ end
342
+
343
+ end
344
+
345
+ end