mondrian-olap 0.3.0 → 0.5.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.
- checksums.yaml +7 -0
- data/Changelog.md +38 -0
- data/LICENSE.txt +1 -1
- data/README.md +302 -0
- data/VERSION +1 -1
- data/lib/mondrian/jars/commons-collections-3.2.jar +0 -0
- data/lib/mondrian/jars/commons-logging-1.1.1.jar +0 -0
- data/lib/mondrian/jars/commons-math-1.1.jar +0 -0
- data/lib/mondrian/jars/eigenbase-properties-1.1.2.jar +0 -0
- data/lib/mondrian/jars/eigenbase-resgen-1.3.1.jar +0 -0
- data/lib/mondrian/jars/eigenbase-xom-1.3.1.jar +0 -0
- data/lib/mondrian/jars/{javacup.jar → javacup-10k.jar} +0 -0
- data/lib/mondrian/jars/log4j-1.2.14.jar +0 -0
- data/lib/mondrian/jars/mondrian.jar +0 -0
- data/lib/mondrian/jars/olap4j-1.0.1.539.jar +0 -0
- data/lib/mondrian/olap.rb +2 -1
- data/lib/mondrian/olap/connection.rb +163 -32
- data/lib/mondrian/olap/cube.rb +163 -24
- data/lib/mondrian/olap/error.rb +57 -0
- data/lib/mondrian/olap/query.rb +52 -17
- data/lib/mondrian/olap/result.rb +298 -6
- data/lib/mondrian/olap/schema.rb +220 -29
- data/lib/mondrian/olap/schema_element.rb +31 -11
- data/lib/mondrian/olap/schema_udf.rb +331 -0
- data/lib/mondrian/olap/version.rb +5 -0
- data/spec/connection_role_spec.rb +130 -0
- data/spec/connection_spec.rb +36 -1
- data/spec/cube_spec.rb +137 -7
- data/spec/fixtures/MondrianTest.xml +4 -4
- data/spec/mondrian_spec.rb +53 -0
- data/spec/query_spec.rb +294 -11
- data/spec/rake_tasks.rb +8 -8
- data/spec/schema_definition_spec.rb +845 -26
- data/spec/spec_helper.rb +26 -17
- data/spec/support/matchers/be_like.rb +2 -2
- metadata +296 -237
- data/.rspec +0 -2
- data/Gemfile +0 -18
- data/README.rdoc +0 -221
- data/RUNNING_TESTS.rdoc +0 -66
- data/Rakefile +0 -46
- data/lib/mondrian/jars/commons-collections-3.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/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/log4j-1.2.8.jar +0 -0
- data/lib/mondrian/jars/olap4j.jar +0 -0
- data/mondrian-olap.gemspec +0 -126
data/spec/rake_tasks.rb
CHANGED
@@ -82,7 +82,7 @@ namespace :db do
|
|
82
82
|
task :define_models => :require_spec_helper do
|
83
83
|
unless MONDRIAN_DRIVER == 'luciddb'
|
84
84
|
class TimeDimension < ActiveRecord::Base
|
85
|
-
|
85
|
+
self.table_name = "time"
|
86
86
|
validates_presence_of :the_date
|
87
87
|
before_create do
|
88
88
|
self.the_day = the_date.strftime("%A")
|
@@ -102,7 +102,7 @@ namespace :db do
|
|
102
102
|
class Customer < ActiveRecord::Base
|
103
103
|
end
|
104
104
|
class Sales < ActiveRecord::Base
|
105
|
-
|
105
|
+
self.table_name = "sales"
|
106
106
|
belongs_to :time_by_day
|
107
107
|
belongs_to :product
|
108
108
|
belongs_to :customer
|
@@ -150,7 +150,7 @@ namespace :db do
|
|
150
150
|
)
|
151
151
|
Product.create!(
|
152
152
|
# LucidDB is not returning inserted ID therefore doing it hard way
|
153
|
-
:product_class_id => ProductClass.
|
153
|
+
:product_class_id => ProductClass.where(:product_category => "Category #{i}").to_a.first.id,
|
154
154
|
:brand_name => "Brand #{i}",
|
155
155
|
:product_name => "Product #{i}"
|
156
156
|
)
|
@@ -223,9 +223,9 @@ namespace :db do
|
|
223
223
|
Sales.delete_all
|
224
224
|
count = 100
|
225
225
|
# LucidDB does not support LIMIT therefore select all and limit in Ruby
|
226
|
-
products = Product.order("id").
|
227
|
-
times = TimeDimension.order("id").
|
228
|
-
customers = Customer.order("id").
|
226
|
+
products = Product.order("id").to_a[0...count]
|
227
|
+
times = TimeDimension.order("id").to_a[0...count]
|
228
|
+
customers = Customer.order("id").to_a[0...count]
|
229
229
|
count.times do |i|
|
230
230
|
Sales.create!(
|
231
231
|
:product_id => products[i].id,
|
@@ -251,9 +251,9 @@ namespace :spec do
|
|
251
251
|
end
|
252
252
|
end
|
253
253
|
|
254
|
-
desc "Run specs with all database drivers"
|
254
|
+
desc "Run specs with all primary database drivers"
|
255
255
|
task :all do
|
256
|
-
%w(mysql postgresql oracle
|
256
|
+
%w(mysql postgresql oracle mssql).each do |driver|
|
257
257
|
Rake::Task["spec:#{driver}"].invoke
|
258
258
|
end
|
259
259
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
describe "Schema definition" do
|
@@ -10,25 +12,25 @@ describe "Schema definition" do
|
|
10
12
|
describe "root element" do
|
11
13
|
it "should render to XML" do
|
12
14
|
@schema.to_xml.should be_like <<-XML
|
13
|
-
<?xml version="1.0"?>
|
15
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
14
16
|
<Schema/>
|
15
17
|
XML
|
16
18
|
end
|
17
19
|
|
18
20
|
it "should render to XML with attributes" do
|
19
21
|
@schema.define('FoodMart') do
|
20
|
-
description 'Demo "FoodMart" schema'
|
22
|
+
description 'Demo "FoodMart" schema āčē'
|
21
23
|
end
|
22
24
|
@schema.to_xml.should be_like <<-XML
|
23
|
-
<?xml version="1.0"?>
|
24
|
-
<Schema description="Demo "FoodMart" schema" name="FoodMart"/>
|
25
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
26
|
+
<Schema description="Demo "FoodMart" schema āčē" name="FoodMart"/>
|
25
27
|
XML
|
26
28
|
end
|
27
29
|
|
28
30
|
it "should render to XML using class method" do
|
29
31
|
schema = Mondrian::OLAP::Schema.define('FoodMart')
|
30
32
|
schema.to_xml.should be_like <<-XML
|
31
|
-
<?xml version="1.0"?>
|
33
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
32
34
|
<Schema name="FoodMart"/>
|
33
35
|
XML
|
34
36
|
end
|
@@ -45,7 +47,7 @@ describe "Schema definition" do
|
|
45
47
|
end
|
46
48
|
end
|
47
49
|
@schema.to_xml.should be_like <<-XML
|
48
|
-
<?xml version="1.0"?>
|
50
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
49
51
|
<Schema name="default">
|
50
52
|
<Cube cache="false" defaultMeasure="Unit Sales" description="Sales cube" enabled="true" name="Sales"/>
|
51
53
|
</Schema>
|
@@ -58,7 +60,7 @@ describe "Schema definition" do
|
|
58
60
|
:description => 'Sales cube', :cache => false, :enabled => true
|
59
61
|
end
|
60
62
|
@schema.to_xml.should be_like <<-XML
|
61
|
-
<?xml version="1.0"?>
|
63
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
62
64
|
<Schema name="default">
|
63
65
|
<Cube cache="false" defaultMeasure="Unit Sales" description="Sales cube" enabled="true" name="Sales"/>
|
64
66
|
</Schema>
|
@@ -74,7 +76,7 @@ describe "Schema definition" do
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
@schema.to_xml.should be_like <<-XML
|
77
|
-
<?xml version="1.0"?>
|
79
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
78
80
|
<Schema name="default">
|
79
81
|
<Cube name="Sales">
|
80
82
|
<Table alias="sales" name="sales_fact"/>
|
@@ -91,7 +93,7 @@ describe "Schema definition" do
|
|
91
93
|
end
|
92
94
|
%w(oracle luciddb).each do |driver|
|
93
95
|
@schema.to_xml(:driver => driver).should be_like <<-XML
|
94
|
-
<?xml version="1.0"?>
|
96
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
95
97
|
<Schema name="default">
|
96
98
|
<Cube name="Sales">
|
97
99
|
<Table alias="SALES" name="SALES_FACT" schema="FACTS"/>
|
@@ -108,7 +110,7 @@ describe "Schema definition" do
|
|
108
110
|
end
|
109
111
|
end
|
110
112
|
@schema.to_xml.should be_like <<-XML
|
111
|
-
<?xml version="1.0"?>
|
113
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
112
114
|
<Schema name="default">
|
113
115
|
<Cube name="Sales">
|
114
116
|
<Table alias="SALES" name="SALES_FACT" schema="FACTS"/>
|
@@ -125,7 +127,7 @@ describe "Schema definition" do
|
|
125
127
|
end
|
126
128
|
%w(oracle luciddb).each do |driver|
|
127
129
|
@schema.to_xml(:driver => driver).should be_like <<-XML
|
128
|
-
<?xml version="1.0"?>
|
130
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
129
131
|
<Schema name="default">
|
130
132
|
<Cube name="Sales">
|
131
133
|
<Table alias="sales" name="sales_fact" schema="facts"/>
|
@@ -144,7 +146,7 @@ describe "Schema definition" do
|
|
144
146
|
end
|
145
147
|
end
|
146
148
|
@schema.to_xml.should be_like <<-XML
|
147
|
-
<?xml version="1.0"?>
|
149
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
148
150
|
<Schema name="default">
|
149
151
|
<Cube name="Sales">
|
150
152
|
<Table alias="sales" name="sales_fact">
|
@@ -166,7 +168,7 @@ describe "Schema definition" do
|
|
166
168
|
end
|
167
169
|
end
|
168
170
|
@schema.to_xml.should be_like <<-XML
|
169
|
-
<?xml version="1.0"?>
|
171
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
170
172
|
<Schema name="default">
|
171
173
|
<Cube name="Sales">
|
172
174
|
<View alias="sales">
|
@@ -195,7 +197,7 @@ describe "Schema definition" do
|
|
195
197
|
end
|
196
198
|
end
|
197
199
|
@schema.to_xml.should be_like <<-XML
|
198
|
-
<?xml version="1.0"?>
|
200
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
199
201
|
<Schema name="default">
|
200
202
|
<Cube name="Sales">
|
201
203
|
<Dimension foreignKey="customer_id" name="Gender">
|
@@ -226,7 +228,7 @@ describe "Schema definition" do
|
|
226
228
|
end
|
227
229
|
end
|
228
230
|
@schema.to_xml.should be_like <<-XML
|
229
|
-
<?xml version="1.0"?>
|
231
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
230
232
|
<Schema name="default">
|
231
233
|
<Cube name="Sales">
|
232
234
|
<Dimension foreignKey="time_id" name="Time">
|
@@ -242,6 +244,39 @@ describe "Schema definition" do
|
|
242
244
|
XML
|
243
245
|
end
|
244
246
|
|
247
|
+
it "should render dimension with hierarchy and level defaults" do
|
248
|
+
@schema.define do
|
249
|
+
cube 'Sales' do
|
250
|
+
dimension 'Time' do
|
251
|
+
foreign_key 'time_id'
|
252
|
+
hierarchy do
|
253
|
+
all_member_name 'All Times' # should add :has_all => true
|
254
|
+
primary_key 'time_id'
|
255
|
+
table 'time_by_day'
|
256
|
+
level 'Year', :column => 'the_year', :type => 'Numeric' # first level should have default :unique_members => true
|
257
|
+
level 'Quarter', :column => 'quarter' # next levels should have default :unique_members => false
|
258
|
+
level 'Month', :column => 'month_of_year', :type => 'Numeric'
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
@schema.to_xml.should be_like <<-XML
|
264
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
265
|
+
<Schema name="default">
|
266
|
+
<Cube name="Sales">
|
267
|
+
<Dimension foreignKey="time_id" name="Time">
|
268
|
+
<Hierarchy allMemberName="All Times" hasAll="true" primaryKey="time_id">
|
269
|
+
<Table name="time_by_day"/>
|
270
|
+
<Level column="the_year" name="Year" type="Numeric" uniqueMembers="true"/>
|
271
|
+
<Level column="quarter" name="Quarter" uniqueMembers="false"/>
|
272
|
+
<Level column="month_of_year" name="Month" type="Numeric" uniqueMembers="false"/>
|
273
|
+
</Hierarchy>
|
274
|
+
</Dimension>
|
275
|
+
</Cube>
|
276
|
+
</Schema>
|
277
|
+
XML
|
278
|
+
end
|
279
|
+
|
245
280
|
it "should render dimension hierarchy with join" do
|
246
281
|
@schema.define do
|
247
282
|
cube 'Sales' do
|
@@ -260,7 +295,7 @@ describe "Schema definition" do
|
|
260
295
|
end
|
261
296
|
end
|
262
297
|
@schema.to_xml.should be_like <<-XML
|
263
|
-
<?xml version="1.0"?>
|
298
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
264
299
|
<Schema name="default">
|
265
300
|
<Cube name="Sales">
|
266
301
|
<Dimension foreignKey="product_id" name="Products">
|
@@ -297,7 +332,7 @@ describe "Schema definition" do
|
|
297
332
|
end
|
298
333
|
end
|
299
334
|
@schema.to_xml(:driver => 'oracle').should be_like <<-XML
|
300
|
-
<?xml version="1.0"?>
|
335
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
301
336
|
<Schema name="default">
|
302
337
|
<Cube name="Sales">
|
303
338
|
<Dimension foreignKey="PRODUCT_ID" name="Products">
|
@@ -316,6 +351,113 @@ describe "Schema definition" do
|
|
316
351
|
XML
|
317
352
|
end
|
318
353
|
|
354
|
+
it "should render dimension hierarchy with nested joins" do
|
355
|
+
@schema.define do
|
356
|
+
cube 'Sales' do
|
357
|
+
dimension 'Products', :foreign_key => 'product_id' do
|
358
|
+
hierarchy :has_all => true, :all_member_name => 'All Products',
|
359
|
+
:primary_key => 'product_id', :primary_key_table => 'product' do
|
360
|
+
join :left_key => 'product_class_id', :right_alias => 'product_class', :right_key => 'product_class_id' do
|
361
|
+
table 'product'
|
362
|
+
join :left_key => 'product_type_id', :right_key => 'product_type_id' do
|
363
|
+
table 'product_class'
|
364
|
+
table 'product_type'
|
365
|
+
end
|
366
|
+
end
|
367
|
+
level 'Product Family', :table => 'product_type', :column => 'product_family', :unique_members => true
|
368
|
+
level 'Product Category', :table => 'product_class', :column => 'product_category', :unique_members => false
|
369
|
+
level 'Brand Name', :table => 'product', :column => 'brand_name', :unique_members => false
|
370
|
+
level 'Product Name', :table => 'product', :column => 'product_name', :unique_members => true
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
@schema.to_xml.should be_like <<-XML
|
376
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
377
|
+
<Schema name="default">
|
378
|
+
<Cube name="Sales">
|
379
|
+
<Dimension foreignKey="product_id" name="Products">
|
380
|
+
<Hierarchy allMemberName="All Products" hasAll="true" primaryKey="product_id" primaryKeyTable="product">
|
381
|
+
<Join leftKey="product_class_id" rightAlias="product_class" rightKey="product_class_id">
|
382
|
+
<Table name="product"/>
|
383
|
+
<Join leftKey="product_type_id" rightKey="product_type_id">
|
384
|
+
<Table name="product_class"/>
|
385
|
+
<Table name="product_type"/>
|
386
|
+
</Join>
|
387
|
+
</Join>
|
388
|
+
<Level column="product_family" name="Product Family" table="product_type" uniqueMembers="true"/>
|
389
|
+
<Level column="product_category" name="Product Category" table="product_class" uniqueMembers="false"/>
|
390
|
+
<Level column="brand_name" name="Brand Name" table="product" uniqueMembers="false"/>
|
391
|
+
<Level column="product_name" name="Product Name" table="product" uniqueMembers="true"/>
|
392
|
+
</Hierarchy>
|
393
|
+
</Dimension>
|
394
|
+
</Cube>
|
395
|
+
</Schema>
|
396
|
+
XML
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|
400
|
+
|
401
|
+
describe "Shared dimension" do
|
402
|
+
it "should render to XML" do
|
403
|
+
@schema.define do
|
404
|
+
dimension 'Gender' do
|
405
|
+
hierarchy do
|
406
|
+
has_all true
|
407
|
+
all_member_name 'All Genders'
|
408
|
+
primary_key 'customer_id'
|
409
|
+
table 'customer'
|
410
|
+
level 'Gender', :column => 'gender', :unique_members => true
|
411
|
+
end
|
412
|
+
end
|
413
|
+
cube 'Sales' do
|
414
|
+
dimension_usage 'Gender', :foreign_key => 'customer_id' # by default :source => 'Gender' will be added
|
415
|
+
end
|
416
|
+
end
|
417
|
+
@schema.to_xml.should be_like <<-XML
|
418
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
419
|
+
<Schema name="default">
|
420
|
+
<Dimension name="Gender">
|
421
|
+
<Hierarchy allMemberName="All Genders" hasAll="true" primaryKey="customer_id">
|
422
|
+
<Table name="customer"/>
|
423
|
+
<Level column="gender" name="Gender" uniqueMembers="true"/>
|
424
|
+
</Hierarchy>
|
425
|
+
</Dimension>
|
426
|
+
<Cube name="Sales">
|
427
|
+
<DimensionUsage foreignKey="customer_id" name="Gender" source="Gender"/>
|
428
|
+
</Cube>
|
429
|
+
</Schema>
|
430
|
+
XML
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
describe "Virtual cube" do
|
435
|
+
it "should render to XML" do
|
436
|
+
@schema.define do
|
437
|
+
virtual_cube 'Warehouse and Sales', :default_measure => 'Store Sales' do
|
438
|
+
virtual_cube_dimension 'Customers', :cube_name => 'Sales'
|
439
|
+
virtual_cube_dimension 'Product'
|
440
|
+
virtual_cube_measure '[Measures].[Store Sales]', :cube_name => 'Sales'
|
441
|
+
calculated_member 'Profit' do
|
442
|
+
dimension 'Measures'
|
443
|
+
formula '[Measures].[Store Sales] - [Measures].[Store Cost]'
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
@schema.to_xml.should be_like <<-XML
|
448
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
449
|
+
<Schema name="default">
|
450
|
+
<VirtualCube defaultMeasure="Store Sales" name="Warehouse and Sales">
|
451
|
+
<VirtualCubeDimension cubeName="Sales" name="Customers"/>
|
452
|
+
<VirtualCubeDimension name="Product"/>
|
453
|
+
<VirtualCubeMeasure cubeName="Sales" name="[Measures].[Store Sales]"/>
|
454
|
+
<CalculatedMember dimension="Measures" name="Profit">
|
455
|
+
<Formula>[Measures].[Store Sales] - [Measures].[Store Cost]</Formula>
|
456
|
+
</CalculatedMember>
|
457
|
+
</VirtualCube>
|
458
|
+
</Schema>
|
459
|
+
XML
|
460
|
+
end
|
319
461
|
end
|
320
462
|
|
321
463
|
describe "Measure" do
|
@@ -326,13 +468,15 @@ describe "Schema definition" do
|
|
326
468
|
column 'unit_sales'
|
327
469
|
aggregator 'sum'
|
328
470
|
end
|
471
|
+
measure 'Store Sales', :column => 'store_sales' # by default should use sum aggregator
|
329
472
|
end
|
330
473
|
end
|
331
474
|
@schema.to_xml.should be_like <<-XML
|
332
|
-
<?xml version="1.0"?>
|
475
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
333
476
|
<Schema name="default">
|
334
477
|
<Cube name="Sales">
|
335
478
|
<Measure aggregator="sum" column="unit_sales" name="Unit Sales"/>
|
479
|
+
<Measure aggregator="sum" column="store_sales" name="Store Sales"/>
|
336
480
|
</Cube>
|
337
481
|
</Schema>
|
338
482
|
XML
|
@@ -348,7 +492,7 @@ describe "Schema definition" do
|
|
348
492
|
end
|
349
493
|
end
|
350
494
|
@schema.to_xml(:driver => 'oracle').should be_like <<-XML
|
351
|
-
<?xml version="1.0"?>
|
495
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
352
496
|
<Schema name="default">
|
353
497
|
<Cube name="Sales">
|
354
498
|
<Measure aggregator="sum" column="UNIT_SALES" name="Unit Sales"/>
|
@@ -368,7 +512,7 @@ describe "Schema definition" do
|
|
368
512
|
end
|
369
513
|
end
|
370
514
|
@schema.to_xml.should be_like <<-XML
|
371
|
-
<?xml version="1.0"?>
|
515
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
372
516
|
<Schema name="default">
|
373
517
|
<Cube name="Sales">
|
374
518
|
<Measure aggregator="sum" name="Double Unit Sales">
|
@@ -394,7 +538,7 @@ describe "Schema definition" do
|
|
394
538
|
end
|
395
539
|
end
|
396
540
|
@schema.to_xml.should be_like <<-XML
|
397
|
-
<?xml version="1.0"?>
|
541
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
398
542
|
<Schema name="default">
|
399
543
|
<Cube name="Sales">
|
400
544
|
<CalculatedMember dimension="Measures" formatString="#,##0.00" name="Profit">
|
@@ -404,6 +548,32 @@ describe "Schema definition" do
|
|
404
548
|
</Schema>
|
405
549
|
XML
|
406
550
|
end
|
551
|
+
|
552
|
+
it "should render embedded cube XML defintion before additional calculated member to XML" do
|
553
|
+
@schema.define do
|
554
|
+
cube 'Sales' do
|
555
|
+
xml <<-XML
|
556
|
+
<Table name="sales_fact_1997"/>
|
557
|
+
XML
|
558
|
+
calculated_member 'Profit' do
|
559
|
+
dimension 'Measures'
|
560
|
+
formula '[Measures].[Store Sales] - [Measures].[Store Cost]'
|
561
|
+
format_string '#,##0.00'
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|
565
|
+
@schema.to_xml.should be_like <<-XML
|
566
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
567
|
+
<Schema name="default">
|
568
|
+
<Cube name="Sales">
|
569
|
+
<Table name="sales_fact_1997"/>
|
570
|
+
<CalculatedMember dimension="Measures" formatString="#,##0.00" name="Profit">
|
571
|
+
<Formula>[Measures].[Store Sales] - [Measures].[Store Cost]</Formula>
|
572
|
+
</CalculatedMember>
|
573
|
+
</Cube>
|
574
|
+
</Schema>
|
575
|
+
XML
|
576
|
+
end
|
407
577
|
end
|
408
578
|
|
409
579
|
describe "Aggregates" do
|
@@ -425,7 +595,7 @@ describe "Schema definition" do
|
|
425
595
|
end
|
426
596
|
end
|
427
597
|
@schema.to_xml.should be_like <<-XML
|
428
|
-
<?xml version="1.0"?>
|
598
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
429
599
|
<Schema name="default">
|
430
600
|
<Cube name="Sales">
|
431
601
|
<Table name="sales_fact_1997">
|
@@ -465,7 +635,7 @@ describe "Schema definition" do
|
|
465
635
|
end
|
466
636
|
end
|
467
637
|
@schema.to_xml.should be_like <<-XML
|
468
|
-
<?xml version="1.0"?>
|
638
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
469
639
|
<Schema name="default">
|
470
640
|
<Cube name="Sales">
|
471
641
|
<Table name="sales_fact_1997">
|
@@ -519,7 +689,7 @@ describe "Schema definition" do
|
|
519
689
|
end
|
520
690
|
end
|
521
691
|
@schema.to_xml.should be_like <<-XML
|
522
|
-
<?xml version="1.0"?>
|
692
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
523
693
|
<Schema name="default">
|
524
694
|
<Cube name="Sales">
|
525
695
|
<Table name="sales_fact_1997">
|
@@ -573,7 +743,7 @@ describe "Schema definition" do
|
|
573
743
|
end
|
574
744
|
end
|
575
745
|
@schema.to_xml.should be_like <<-XML
|
576
|
-
<?xml version="1.0"?>
|
746
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
577
747
|
<Schema name="default">
|
578
748
|
<Cube name="Sales">
|
579
749
|
<Dimension foreignKey="employee_id" name="Employees">
|
@@ -594,6 +764,615 @@ describe "Schema definition" do
|
|
594
764
|
end
|
595
765
|
end
|
596
766
|
|
767
|
+
describe "Element annotations" do
|
768
|
+
it "should render XML from block of elements" do
|
769
|
+
@schema.define do
|
770
|
+
cube 'Sales' do
|
771
|
+
annotations do
|
772
|
+
annotation 'key1', 'value1'
|
773
|
+
annotation 'key2', 'value2'
|
774
|
+
end
|
775
|
+
measure 'Unit Sales', :column => 'unit_sales' do
|
776
|
+
annotations do
|
777
|
+
annotation 'key3', 'value3'
|
778
|
+
end
|
779
|
+
end
|
780
|
+
end
|
781
|
+
end
|
782
|
+
@schema.to_xml.should be_like <<-XML
|
783
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
784
|
+
<Schema name="default">
|
785
|
+
<Cube name="Sales">
|
786
|
+
<Annotations>
|
787
|
+
<Annotation name="key1">value1</Annotation>
|
788
|
+
<Annotation name="key2">value2</Annotation>
|
789
|
+
</Annotations>
|
790
|
+
<Measure aggregator="sum" column="unit_sales" name="Unit Sales">
|
791
|
+
<Annotations>
|
792
|
+
<Annotation name="key3">value3</Annotation>
|
793
|
+
</Annotations>
|
794
|
+
</Measure>
|
795
|
+
</Cube>
|
796
|
+
</Schema>
|
797
|
+
XML
|
798
|
+
end
|
799
|
+
|
800
|
+
it "should render XML from hash options" do
|
801
|
+
@schema.define do
|
802
|
+
cube 'Sales' do
|
803
|
+
annotations :key1 => 'value1', :key2 => 'value2'
|
804
|
+
measure 'Unit Sales', :column => 'unit_sales', :annotations => {:key3 => 'value3'}
|
805
|
+
end
|
806
|
+
end
|
807
|
+
@schema.to_xml.should be_like <<-XML
|
808
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
809
|
+
<Schema name="default">
|
810
|
+
<Cube name="Sales">
|
811
|
+
<Annotations>
|
812
|
+
<Annotation name="key1">value1</Annotation>
|
813
|
+
<Annotation name="key2">value2</Annotation>
|
814
|
+
</Annotations>
|
815
|
+
<Measure aggregator="sum" column="unit_sales" name="Unit Sales">
|
816
|
+
<Annotations>
|
817
|
+
<Annotation name="key3">value3</Annotation>
|
818
|
+
</Annotations>
|
819
|
+
</Measure>
|
820
|
+
</Cube>
|
821
|
+
</Schema>
|
822
|
+
XML
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
describe "User defined functions and formatters in JavaScript" do
|
827
|
+
before(:each) do
|
828
|
+
@schema.define do
|
829
|
+
cube 'Sales' do
|
830
|
+
table 'sales'
|
831
|
+
dimension 'Customers', :foreign_key => 'customer_id' do
|
832
|
+
hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
|
833
|
+
table 'customers'
|
834
|
+
level 'Name', :column => 'fullname' do
|
835
|
+
member_formatter { javascript "return member.getName().toUpperCase();" }
|
836
|
+
property 'City', :column => 'city' do
|
837
|
+
property_formatter { javascript "return propertyValue.toUpperCase();" }
|
838
|
+
end
|
839
|
+
end
|
840
|
+
end
|
841
|
+
end
|
842
|
+
calculated_member 'Factorial' do
|
843
|
+
dimension 'Measures'
|
844
|
+
formula 'Factorial(6)'
|
845
|
+
cell_formatter do
|
846
|
+
javascript <<-JS
|
847
|
+
var s = value.toString();
|
848
|
+
while (s.length < 20) {
|
849
|
+
s = "0" + s;
|
850
|
+
}
|
851
|
+
return s;
|
852
|
+
JS
|
853
|
+
end
|
854
|
+
end
|
855
|
+
calculated_member 'City' do
|
856
|
+
dimension 'Measures'
|
857
|
+
formula "[Customers].CurrentMember.Properties('City')"
|
858
|
+
end
|
859
|
+
end
|
860
|
+
user_defined_function 'Factorial' do
|
861
|
+
javascript <<-JS
|
862
|
+
function getParameterTypes() {
|
863
|
+
return new Array(
|
864
|
+
new mondrian.olap.type.NumericType());
|
865
|
+
}
|
866
|
+
function getReturnType(parameterTypes) {
|
867
|
+
return new mondrian.olap.type.NumericType();
|
868
|
+
}
|
869
|
+
function execute(evaluator, arguments) {
|
870
|
+
var n = arguments[0].evaluateScalar(evaluator);
|
871
|
+
return factorial(n);
|
872
|
+
}
|
873
|
+
function factorial(n) {
|
874
|
+
return n <= 1 ? 1 : n * factorial(n - 1);
|
875
|
+
}
|
876
|
+
JS
|
877
|
+
end
|
878
|
+
end
|
879
|
+
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
880
|
+
end
|
881
|
+
|
882
|
+
it "should render XML" do
|
883
|
+
@schema.to_xml.should be_like <<-XML
|
884
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
885
|
+
<Schema name="default">
|
886
|
+
<Cube name="Sales">
|
887
|
+
<Table name="sales"/>
|
888
|
+
<Dimension foreignKey="customer_id" name="Customers">
|
889
|
+
<Hierarchy allMemberName="All Customers" hasAll="true" primaryKey="id">
|
890
|
+
<Table name="customers"/>
|
891
|
+
<Level column="fullname" name="Name" uniqueMembers="true">
|
892
|
+
<MemberFormatter>
|
893
|
+
<Script language="JavaScript">return member.getName().toUpperCase();</Script>
|
894
|
+
</MemberFormatter>
|
895
|
+
<Property column="city" name="City">
|
896
|
+
<PropertyFormatter>
|
897
|
+
<Script language="JavaScript">return propertyValue.toUpperCase();</Script>
|
898
|
+
</PropertyFormatter>
|
899
|
+
</Property>
|
900
|
+
</Level>
|
901
|
+
</Hierarchy>
|
902
|
+
</Dimension>
|
903
|
+
<CalculatedMember dimension="Measures" name="Factorial">
|
904
|
+
<Formula>Factorial(6)</Formula>
|
905
|
+
<CellFormatter>
|
906
|
+
<Script language="JavaScript">
|
907
|
+
var s = value.toString();
|
908
|
+
while (s.length < 20) {
|
909
|
+
s = "0" + s;
|
910
|
+
}
|
911
|
+
return s;
|
912
|
+
</Script>
|
913
|
+
</CellFormatter>
|
914
|
+
</CalculatedMember>
|
915
|
+
<CalculatedMember dimension="Measures" name="City">
|
916
|
+
<Formula>[Customers].CurrentMember.Properties('City')</Formula>
|
917
|
+
</CalculatedMember>
|
918
|
+
</Cube>
|
919
|
+
<UserDefinedFunction name="Factorial">
|
920
|
+
<Script language="JavaScript">
|
921
|
+
function getParameterTypes() {
|
922
|
+
return new Array(
|
923
|
+
new mondrian.olap.type.NumericType());
|
924
|
+
}
|
925
|
+
function getReturnType(parameterTypes) {
|
926
|
+
return new mondrian.olap.type.NumericType();
|
927
|
+
}
|
928
|
+
function execute(evaluator, arguments) {
|
929
|
+
var n = arguments[0].evaluateScalar(evaluator);
|
930
|
+
return factorial(n);
|
931
|
+
}
|
932
|
+
function factorial(n) {
|
933
|
+
return n <= 1 ? 1 : n * factorial(n - 1);
|
934
|
+
}
|
935
|
+
</Script>
|
936
|
+
</UserDefinedFunction>
|
937
|
+
</Schema>
|
938
|
+
XML
|
939
|
+
end
|
940
|
+
|
941
|
+
it "should execute user defined function" do
|
942
|
+
result = @olap.from('Sales').columns('[Measures].[Factorial]').execute
|
943
|
+
value = 1*2*3*4*5*6
|
944
|
+
result.values.should == [value]
|
945
|
+
result.formatted_values.should == ["%020d" % value]
|
946
|
+
end
|
947
|
+
|
948
|
+
it "should format members and properties" do
|
949
|
+
result = @olap.from('Sales').columns('[Measures].[City]').rows('[Customers].[All Customers].Children').execute
|
950
|
+
result.row_members.each_with_index do |member, i|
|
951
|
+
member.caption.should == member.name.upcase
|
952
|
+
city = member.property_value('City')
|
953
|
+
result.formatted_values[i].first.should == city
|
954
|
+
member.property_formatted_value('City').should == city.upcase
|
955
|
+
end
|
956
|
+
end
|
957
|
+
end
|
958
|
+
|
959
|
+
describe "User defined functions and formatters in CoffeeScript" do
|
960
|
+
before(:each) do
|
961
|
+
@schema.define do
|
962
|
+
cube 'Sales' do
|
963
|
+
table 'sales'
|
964
|
+
dimension 'Customers', :foreign_key => 'customer_id' do
|
965
|
+
hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
|
966
|
+
table 'customers'
|
967
|
+
level 'Name', :column => 'fullname' do
|
968
|
+
member_formatter { coffeescript "member.getName().toUpperCase()" }
|
969
|
+
property 'City', :column => 'city' do
|
970
|
+
property_formatter { coffeescript "propertyValue.toUpperCase()" }
|
971
|
+
end
|
972
|
+
end
|
973
|
+
end
|
974
|
+
end
|
975
|
+
calculated_member 'Factorial' do
|
976
|
+
dimension 'Measures'
|
977
|
+
formula 'Factorial(6)'
|
978
|
+
cell_formatter do
|
979
|
+
coffeescript <<-JS
|
980
|
+
s = value.toString()
|
981
|
+
s = "0" + s while s.length < 20
|
982
|
+
s
|
983
|
+
JS
|
984
|
+
end
|
985
|
+
end
|
986
|
+
calculated_member 'City' do
|
987
|
+
dimension 'Measures'
|
988
|
+
formula "[Customers].CurrentMember.Properties('City')"
|
989
|
+
end
|
990
|
+
end
|
991
|
+
user_defined_function 'Factorial' do
|
992
|
+
coffeescript <<-JS
|
993
|
+
parameters: ["Numeric"]
|
994
|
+
returns: "Numeric"
|
995
|
+
execute: (n) ->
|
996
|
+
if n <= 1 then 1 else n * @execute(n - 1)
|
997
|
+
JS
|
998
|
+
end
|
999
|
+
user_defined_function 'UpperName' do
|
1000
|
+
coffeescript <<-JS
|
1001
|
+
parameters: ["Member"]
|
1002
|
+
returns: "String"
|
1003
|
+
syntax: "Property"
|
1004
|
+
execute: (member) ->
|
1005
|
+
member.getName().toUpperCase()
|
1006
|
+
JS
|
1007
|
+
end
|
1008
|
+
user_defined_function 'toUpperName' do
|
1009
|
+
coffeescript <<-JS
|
1010
|
+
parameters: ["Member", "String"]
|
1011
|
+
returns: "String"
|
1012
|
+
syntax: "Method"
|
1013
|
+
execute: (member, dummy) ->
|
1014
|
+
member.getName().toUpperCase()
|
1015
|
+
JS
|
1016
|
+
end
|
1017
|
+
end
|
1018
|
+
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
it "should execute user defined function" do
|
1022
|
+
result = @olap.from('Sales').columns('[Measures].[Factorial]').execute
|
1023
|
+
value = 1*2*3*4*5*6
|
1024
|
+
result.values.should == [value]
|
1025
|
+
result.formatted_values.should == ["%020d" % value]
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
it "should format members and properties" do
|
1029
|
+
result = @olap.from('Sales').columns('[Measures].[City]').rows('[Customers].[All Customers].Children').execute
|
1030
|
+
result.row_members.each_with_index do |member, i|
|
1031
|
+
member.caption.should == member.name.upcase
|
1032
|
+
city = member.property_value('City')
|
1033
|
+
result.formatted_values[i].first.should == city
|
1034
|
+
member.property_formatted_value('City').should == city.upcase
|
1035
|
+
end
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
it "should execute user defined property on member" do
|
1039
|
+
result = @olap.from('Sales').
|
1040
|
+
with_member('[Measures].[Upper Name]').as('[Customers].CurrentMember.UpperName').
|
1041
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1042
|
+
result.row_members.each_with_index do |member, i|
|
1043
|
+
result.values[i].should == [member.name.upcase]
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
it "should execute user defined method on member" do
|
1048
|
+
result = @olap.from('Sales').
|
1049
|
+
with_member('[Measures].[Upper Name]').as("[Customers].CurrentMember.toUpperName('dummy')").
|
1050
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1051
|
+
result.row_members.each_with_index do |member, i|
|
1052
|
+
result.values[i].should == [member.name.upcase]
|
1053
|
+
end
|
1054
|
+
end
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
describe "User defined functions and formatters in Ruby" do
|
1058
|
+
before(:each) do
|
1059
|
+
@schema.define do
|
1060
|
+
cube 'Sales' do
|
1061
|
+
table 'sales'
|
1062
|
+
dimension 'Customers', :foreign_key => 'customer_id' do
|
1063
|
+
hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
|
1064
|
+
table 'customers'
|
1065
|
+
level 'Name', :column => 'fullname' do
|
1066
|
+
member_formatter { ruby {|member| member.getName().upcase } }
|
1067
|
+
property 'City', :column => 'city' do
|
1068
|
+
property_formatter { ruby {|member, property_name, property_value| property_value.upcase} }
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
calculated_member 'Factorial' do
|
1074
|
+
dimension 'Measures'
|
1075
|
+
formula 'Factorial(6)'
|
1076
|
+
cell_formatter { ruby {|value| "%020d" % value} }
|
1077
|
+
end
|
1078
|
+
calculated_member 'City' do
|
1079
|
+
dimension 'Measures'
|
1080
|
+
formula "[Customers].CurrentMember.Properties('City')"
|
1081
|
+
end
|
1082
|
+
end
|
1083
|
+
user_defined_function 'Factorial' do
|
1084
|
+
ruby do
|
1085
|
+
parameters :numeric
|
1086
|
+
returns :numeric
|
1087
|
+
def call(n)
|
1088
|
+
n <= 1 ? 1 : n * call(n - 1)
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
user_defined_function 'UpperName' do
|
1093
|
+
ruby do
|
1094
|
+
parameters :member
|
1095
|
+
returns :string
|
1096
|
+
syntax :property
|
1097
|
+
def call(member)
|
1098
|
+
member.getName.upcase
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
user_defined_function 'toUpperName' do
|
1103
|
+
ruby do
|
1104
|
+
parameters :member, :string
|
1105
|
+
returns :string
|
1106
|
+
syntax :method
|
1107
|
+
def call(member, dummy)
|
1108
|
+
member.getName.upcase
|
1109
|
+
end
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
user_defined_function 'firstUpperName' do
|
1113
|
+
ruby do
|
1114
|
+
parameters :set
|
1115
|
+
returns :string
|
1116
|
+
syntax :property
|
1117
|
+
def call(set)
|
1118
|
+
set.first.getName.upcase
|
1119
|
+
end
|
1120
|
+
end
|
1121
|
+
end
|
1122
|
+
user_defined_function 'firstToUpperName' do
|
1123
|
+
ruby do
|
1124
|
+
parameters :set, :string
|
1125
|
+
returns :string
|
1126
|
+
syntax :method
|
1127
|
+
def call(set, dummy)
|
1128
|
+
set.first.getName.upcase
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
end
|
1132
|
+
user_defined_function 'firstChildUpperName' do
|
1133
|
+
ruby do
|
1134
|
+
parameters :hierarchy
|
1135
|
+
returns :string
|
1136
|
+
syntax :property
|
1137
|
+
def call_with_evaluator(evaluator, hierarchy)
|
1138
|
+
evaluator.getSchemaReader.getMemberChildren(hierarchy.getDefaultMember).first.getName.upcase
|
1139
|
+
end
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
user_defined_function 'firstLevelChildUpperName' do
|
1143
|
+
ruby do
|
1144
|
+
parameters :level
|
1145
|
+
returns :string
|
1146
|
+
syntax :property
|
1147
|
+
def call_with_evaluator(evaluator, level)
|
1148
|
+
evaluator.getSchemaReader.getLevelMembers(level, false).first.getName.upcase
|
1149
|
+
end
|
1150
|
+
end
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
it "should execute user defined function" do
|
1157
|
+
result = @olap.from('Sales').columns('[Measures].[Factorial]').execute
|
1158
|
+
value = 1*2*3*4*5*6
|
1159
|
+
result.values.should == [value]
|
1160
|
+
result.formatted_values.should == ["%020d" % value]
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
it "should format members and properties" do
|
1164
|
+
result = @olap.from('Sales').columns('[Measures].[City]').rows('[Customers].[All Customers].Children').execute
|
1165
|
+
result.row_members.each_with_index do |member, i|
|
1166
|
+
member.caption.should == member.name.upcase
|
1167
|
+
city = member.property_value('City')
|
1168
|
+
result.formatted_values[i].first.should == city
|
1169
|
+
member.property_formatted_value('City').should == city.upcase
|
1170
|
+
end
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
it "should execute user defined property on member" do
|
1174
|
+
result = @olap.from('Sales').
|
1175
|
+
with_member('[Measures].[Upper Name]').as('[Customers].CurrentMember.UpperName').
|
1176
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1177
|
+
result.row_members.each_with_index do |member, i|
|
1178
|
+
result.values[i].should == [member.name.upcase]
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
it "should execute user defined method on member" do
|
1183
|
+
result = @olap.from('Sales').
|
1184
|
+
with_member('[Measures].[Upper Name]').as("[Customers].CurrentMember.toUpperName('dummy')").
|
1185
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1186
|
+
result.row_members.each_with_index do |member, i|
|
1187
|
+
result.values[i].should == [member.name.upcase]
|
1188
|
+
end
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
it "should execute user defined property on set" do
|
1192
|
+
result = @olap.from('Sales').
|
1193
|
+
with_member('[Measures].[Upper Name]').as("{[Customers].CurrentMember}.firstUpperName").
|
1194
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1195
|
+
result.row_members.each_with_index do |member, i|
|
1196
|
+
result.values[i].should == [member.name.upcase]
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
it "should execute user defined method on set" do
|
1201
|
+
result = @olap.from('Sales').
|
1202
|
+
with_member('[Measures].[Upper Name]').as("{[Customers].CurrentMember}.firstToUpperName('dummy')").
|
1203
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1204
|
+
result.row_members.each_with_index do |member, i|
|
1205
|
+
result.values[i].should == [member.name.upcase]
|
1206
|
+
end
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
it "should execute user defined property on hierarchy" do
|
1210
|
+
result = @olap.from('Sales').
|
1211
|
+
with_member('[Measures].[Upper Name]').as("[Customers].firstChildUpperName").
|
1212
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1213
|
+
first_member = result.row_members.first
|
1214
|
+
result.row_members.each_with_index do |member, i|
|
1215
|
+
result.values[i].should == [first_member.name.upcase]
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
it "should execute user defined property on level" do
|
1220
|
+
result = @olap.from('Sales').
|
1221
|
+
with_member('[Measures].[Upper Name]').as("[Customers].[Name].firstLevelChildUpperName").
|
1222
|
+
columns('[Measures].[Upper Name]').rows('[Customers].Children').execute
|
1223
|
+
first_member = result.row_members.first
|
1224
|
+
result.row_members.each_with_index do |member, i|
|
1225
|
+
result.values[i].should == [first_member.name.upcase]
|
1226
|
+
end
|
1227
|
+
end
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
describe "Shared user defined functions in Ruby" do
|
1231
|
+
before(:each) do
|
1232
|
+
shared_schema = Mondrian::OLAP::Schema.define do
|
1233
|
+
user_defined_function 'Factorial' do
|
1234
|
+
ruby :shared do
|
1235
|
+
parameters :numeric
|
1236
|
+
returns :numeric
|
1237
|
+
def call(n)
|
1238
|
+
n <= 1 ? 1 : n * call(n - 1)
|
1239
|
+
end
|
1240
|
+
end
|
1241
|
+
end
|
1242
|
+
user_defined_function 'UpperName' do
|
1243
|
+
ruby :shared do
|
1244
|
+
parameters :member
|
1245
|
+
returns :string
|
1246
|
+
syntax :property
|
1247
|
+
def call(member)
|
1248
|
+
member.getName.upcase
|
1249
|
+
end
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
user_defined_function 'toUpperName' do
|
1253
|
+
ruby :shared do
|
1254
|
+
parameters :member, :string
|
1255
|
+
returns :string
|
1256
|
+
syntax :method
|
1257
|
+
def call(member, dummy)
|
1258
|
+
member.getName.upcase
|
1259
|
+
end
|
1260
|
+
end
|
1261
|
+
end
|
1262
|
+
user_defined_cell_formatter 'Integer20Digits' do
|
1263
|
+
ruby :shared do |value|
|
1264
|
+
"%020d" % value
|
1265
|
+
end
|
1266
|
+
end
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
@schema.define do
|
1270
|
+
include_schema shared_schema
|
1271
|
+
|
1272
|
+
cube 'Sales' do
|
1273
|
+
table 'sales'
|
1274
|
+
dimension 'Customers', :foreign_key => 'customer_id' do
|
1275
|
+
hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
|
1276
|
+
table 'customers'
|
1277
|
+
level 'Name', :column => 'fullname'
|
1278
|
+
end
|
1279
|
+
end
|
1280
|
+
measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum', :format_string => '#,##0'
|
1281
|
+
calculated_member 'Factorial' do
|
1282
|
+
dimension 'Measures'
|
1283
|
+
formula 'Factorial(6)'
|
1284
|
+
cell_formatter 'Integer20Digits'
|
1285
|
+
end
|
1286
|
+
end
|
1287
|
+
end
|
1288
|
+
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
it "should render XML" do
|
1292
|
+
@schema.to_xml.should be_like <<-XML
|
1293
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
1294
|
+
<Schema name="default">
|
1295
|
+
<Cube name="Sales">
|
1296
|
+
<Table name="sales"/>
|
1297
|
+
<Dimension foreignKey="customer_id" name="Customers">
|
1298
|
+
<Hierarchy allMemberName="All Customers" hasAll="true" primaryKey="id">
|
1299
|
+
<Table name="customers"/>
|
1300
|
+
<Level column="fullname" name="Name" uniqueMembers="true"/>
|
1301
|
+
</Hierarchy>
|
1302
|
+
</Dimension>
|
1303
|
+
<Measure aggregator="sum" column="unit_sales" formatString="#,##0" name="Unit Sales"/>
|
1304
|
+
<CalculatedMember dimension="Measures" name="Factorial">
|
1305
|
+
<Formula>Factorial(6)</Formula>
|
1306
|
+
<CellFormatter className="rubyobj.Mondrian.OLAP.Schema.CellFormatter.Integer20DigitsUdf"/>
|
1307
|
+
</CalculatedMember>
|
1308
|
+
</Cube>
|
1309
|
+
<UserDefinedFunction className="rubyobj.Mondrian.OLAP.Schema.UserDefinedFunction.FactorialUdf" name="Factorial"/>
|
1310
|
+
<UserDefinedFunction className="rubyobj.Mondrian.OLAP.Schema.UserDefinedFunction.UppernameUdf" name="UpperName"/>
|
1311
|
+
<UserDefinedFunction className="rubyobj.Mondrian.OLAP.Schema.UserDefinedFunction.TouppernameUdf" name="toUpperName"/>
|
1312
|
+
</Schema>
|
1313
|
+
XML
|
1314
|
+
end
|
1315
|
+
|
1316
|
+
it "should execute user defined function" do
|
1317
|
+
result = @olap.from('Sales').columns('[Measures].[Factorial]').execute
|
1318
|
+
value = 1*2*3*4*5*6
|
1319
|
+
result.values.should == [value]
|
1320
|
+
result.formatted_values.should == ["%020d" % value]
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
it "should get measure cell formatter name" do
|
1324
|
+
@olap.cube('Sales').member('[Measures].[Factorial]').cell_formatter_name.should == 'Integer20Digits'
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
it "should not get measure cell formatter name if not specified" do
|
1328
|
+
@olap.cube('Sales').member('[Measures].[Unit Sales]').cell_formatter_name.should be_nil
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
it "should get measure format string" do
|
1332
|
+
@olap.cube('Sales').member('[Measures].[Unit Sales]').format_string.should == '#,##0'
|
1333
|
+
end
|
1334
|
+
|
1335
|
+
it "should not get measure format string if not specified" do
|
1336
|
+
@olap.cube('Sales').member('[Measures].[Factorial]').format_string.should be_nil
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
describe "Roles" do
|
1342
|
+
it "should render XML" do
|
1343
|
+
@schema.define do
|
1344
|
+
role 'California manager' do
|
1345
|
+
schema_grant :access => 'none' do
|
1346
|
+
cube_grant :cube => 'Sales', :access => 'all' do
|
1347
|
+
dimension_grant :dimension => '[Measures]', :access => 'all'
|
1348
|
+
hierarchy_grant :hierarchy => '[Customers]', :access => 'custom',
|
1349
|
+
:top_level => '[Customers].[State Province]', :bottom_level => '[Customers].[City]' do
|
1350
|
+
member_grant :member => '[Customers].[USA].[CA]', :access => 'all'
|
1351
|
+
member_grant :member => '[Customers].[USA].[CA].[Los Angeles]', :access => 'none'
|
1352
|
+
end
|
1353
|
+
end
|
1354
|
+
end
|
1355
|
+
end
|
1356
|
+
end
|
1357
|
+
@schema.to_xml.should be_like <<-XML
|
1358
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
1359
|
+
<Schema name="default">
|
1360
|
+
<Role name="California manager">
|
1361
|
+
<SchemaGrant access="none">
|
1362
|
+
<CubeGrant access="all" cube="Sales">
|
1363
|
+
<DimensionGrant access="all" dimension="[Measures]"/>
|
1364
|
+
<HierarchyGrant access="custom" bottomLevel="[Customers].[City]" hierarchy="[Customers]" topLevel="[Customers].[State Province]">
|
1365
|
+
<MemberGrant access="all" member="[Customers].[USA].[CA]"/>
|
1366
|
+
<MemberGrant access="none" member="[Customers].[USA].[CA].[Los Angeles]"/>
|
1367
|
+
</HierarchyGrant>
|
1368
|
+
</CubeGrant>
|
1369
|
+
</SchemaGrant>
|
1370
|
+
</Role>
|
1371
|
+
</Schema>
|
1372
|
+
XML
|
1373
|
+
end
|
1374
|
+
end
|
1375
|
+
|
597
1376
|
end
|
598
1377
|
|
599
1378
|
describe "connection with schema" do
|
@@ -636,4 +1415,44 @@ describe "Schema definition" do
|
|
636
1415
|
|
637
1416
|
end
|
638
1417
|
|
639
|
-
|
1418
|
+
describe "errors" do
|
1419
|
+
before(:each) do
|
1420
|
+
@schema = Mondrian::OLAP::Schema.new
|
1421
|
+
end
|
1422
|
+
|
1423
|
+
it "should raise error when invalid schema" do
|
1424
|
+
@schema.define do
|
1425
|
+
cube 'Sales' do
|
1426
|
+
end
|
1427
|
+
end
|
1428
|
+
expect {
|
1429
|
+
Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
1430
|
+
}.to raise_error {|e|
|
1431
|
+
e.should be_kind_of(Mondrian::OLAP::Error)
|
1432
|
+
e.message.should == "mondrian.olap.MondrianException: Mondrian Error:Internal error: Must specify fact table of cube 'Sales'"
|
1433
|
+
e.root_cause_message.should == "Internal error: Must specify fact table of cube 'Sales'"
|
1434
|
+
}
|
1435
|
+
end
|
1436
|
+
|
1437
|
+
it "should raise error when invalid calculated member formula" do
|
1438
|
+
@schema.define do
|
1439
|
+
cube 'Sales' do
|
1440
|
+
table 'sales'
|
1441
|
+
calculated_member 'Dummy' do
|
1442
|
+
dimension 'Measures'
|
1443
|
+
formula 'Dummy(123)'
|
1444
|
+
end
|
1445
|
+
end
|
1446
|
+
end
|
1447
|
+
expect {
|
1448
|
+
Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
1449
|
+
}.to raise_error {|e|
|
1450
|
+
e.should be_kind_of(Mondrian::OLAP::Error)
|
1451
|
+
e.message.should == "mondrian.olap.MondrianException: Mondrian Error:Named set in cube 'Sales' has bad formula"
|
1452
|
+
e.root_cause_message.should == "No function matches signature 'Dummy(<Numeric Expression>)'"
|
1453
|
+
}
|
1454
|
+
end
|
1455
|
+
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
end
|