mondrian-olap 0.1.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/.rspec +2 -0
- data/Gemfile +15 -0
- data/LICENSE-Mondrian.html +259 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +219 -0
- data/RUNNING_TESTS.rdoc +41 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/mondrian-olap.rb +1 -0
- data/lib/mondrian/jars/commons-collections-3.1.jar +0 -0
- data/lib/mondrian/jars/commons-dbcp-1.2.1.jar +0 -0
- data/lib/mondrian/jars/commons-logging-1.0.4.jar +0 -0
- data/lib/mondrian/jars/commons-math-1.0.jar +0 -0
- data/lib/mondrian/jars/commons-pool-1.2.jar +0 -0
- data/lib/mondrian/jars/commons-vfs-1.0.jar +0 -0
- data/lib/mondrian/jars/eigenbase-properties.jar +0 -0
- data/lib/mondrian/jars/eigenbase-resgen.jar +0 -0
- data/lib/mondrian/jars/eigenbase-xom.jar +0 -0
- data/lib/mondrian/jars/javacup.jar +0 -0
- data/lib/mondrian/jars/log4j-1.2.8.jar +0 -0
- data/lib/mondrian/jars/log4j.properties +18 -0
- data/lib/mondrian/jars/mondrian.jar +0 -0
- data/lib/mondrian/jars/olap4j.jar +0 -0
- data/lib/mondrian/olap.rb +14 -0
- data/lib/mondrian/olap/connection.rb +122 -0
- data/lib/mondrian/olap/cube.rb +236 -0
- data/lib/mondrian/olap/query.rb +313 -0
- data/lib/mondrian/olap/result.rb +155 -0
- data/lib/mondrian/olap/schema.rb +158 -0
- data/lib/mondrian/olap/schema_element.rb +123 -0
- data/mondrian-olap.gemspec +116 -0
- data/spec/connection_spec.rb +56 -0
- data/spec/cube_spec.rb +259 -0
- data/spec/fixtures/MondrianTest.xml +128 -0
- data/spec/fixtures/MondrianTestOracle.xml +128 -0
- data/spec/query_spec.rb +582 -0
- data/spec/rake_tasks.rb +185 -0
- data/spec/schema_definition_spec.rb +345 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/matchers/be_like.rb +24 -0
- metadata +217 -0
data/spec/rake_tasks.rb
ADDED
@@ -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 "FoodMart" 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
|