mondrian-olap 0.8.0 → 1.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.
- checksums.yaml +5 -5
- data/Changelog.md +36 -0
- data/LICENSE.txt +1 -1
- data/README.md +5 -2
- data/VERSION +1 -1
- data/lib/mondrian/jars/commons-collections-3.2.2.jar +0 -0
- data/lib/mondrian/jars/commons-lang-2.6.jar +0 -0
- data/lib/mondrian/jars/commons-logging-1.2.jar +0 -0
- data/lib/mondrian/jars/commons-vfs2-2.2.jar +0 -0
- data/lib/mondrian/jars/eigenbase-xom-1.3.5.jar +0 -0
- data/lib/mondrian/jars/log4j.properties +2 -4
- data/lib/mondrian/jars/mondrian-8.3.0.5.jar +0 -0
- data/lib/mondrian/olap/connection.rb +112 -16
- data/lib/mondrian/olap/cube.rb +9 -2
- data/lib/mondrian/olap/error.rb +37 -8
- data/lib/mondrian/olap/query.rb +14 -17
- data/lib/mondrian/olap/result.rb +73 -40
- data/lib/mondrian/olap/schema.rb +1 -0
- data/lib/mondrian/olap/schema_element.rb +20 -4
- data/lib/mondrian/olap/schema_udf.rb +21 -16
- data/spec/connection_role_spec.rb +65 -12
- data/spec/connection_spec.rb +2 -0
- data/spec/cube_cache_control_spec.rb +16 -12
- data/spec/query_spec.rb +157 -21
- data/spec/schema_definition_spec.rb +151 -55
- data/spec/spec_helper.rb +75 -0
- metadata +65 -64
- data/lib/mondrian/jars/commons-collections-3.2.1.jar +0 -0
- data/lib/mondrian/jars/commons-logging-1.1.1.jar +0 -0
- data/lib/mondrian/jars/commons-vfs2-2.1-20150824.jar +0 -0
- data/lib/mondrian/jars/eigenbase-xom-1.3.1.jar +0 -0
- data/lib/mondrian/jars/mondrian-3.12.0.6-237.jar +0 -0
data/lib/mondrian/olap/query.rb
CHANGED
@@ -79,7 +79,7 @@ module Mondrian
|
|
79
79
|
self
|
80
80
|
end
|
81
81
|
|
82
|
-
def filter(condition, options={})
|
82
|
+
def filter(condition, options = {})
|
83
83
|
raise ArgumentError, "cannot use filter method before axis or with_set method" unless @current_set
|
84
84
|
@current_set.replace [:filter, @current_set.clone, condition]
|
85
85
|
@current_set << options[:as] if options[:as]
|
@@ -138,7 +138,7 @@ module Mondrian
|
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
|
-
def hierarchize(order=nil, all=nil)
|
141
|
+
def hierarchize(order = nil, all = nil)
|
142
142
|
raise ArgumentError, "cannot use hierarchize method before axis or with_set method" unless @current_set
|
143
143
|
order = order && order.to_s.upcase
|
144
144
|
raise ArgumentError, "invalid hierarchize order #{order.inspect}" unless order.nil? || order == 'POST'
|
@@ -152,7 +152,7 @@ module Mondrian
|
|
152
152
|
self
|
153
153
|
end
|
154
154
|
|
155
|
-
def hierarchize_all(order=nil)
|
155
|
+
def hierarchize_all(order = nil)
|
156
156
|
hierarchize(order, :all)
|
157
157
|
end
|
158
158
|
|
@@ -236,19 +236,15 @@ module Mondrian
|
|
236
236
|
end
|
237
237
|
|
238
238
|
def execute(parameters = {})
|
239
|
-
|
240
|
-
@connection.execute to_mdx, parameters
|
241
|
-
end
|
239
|
+
@connection.execute to_mdx, parameters
|
242
240
|
end
|
243
241
|
|
244
242
|
def execute_drill_through(options = {})
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
@connection.execute_drill_through drill_through_mdx
|
251
|
-
end
|
243
|
+
drill_through_mdx = "DRILLTHROUGH "
|
244
|
+
drill_through_mdx << "MAXROWS #{options[:max_rows]} " if options[:max_rows]
|
245
|
+
drill_through_mdx << to_mdx
|
246
|
+
drill_through_mdx << " RETURN #{Array(options[:return]).join(',')}" if options[:return]
|
247
|
+
@connection.execute_drill_through drill_through_mdx
|
252
248
|
end
|
253
249
|
|
254
250
|
private
|
@@ -300,10 +296,10 @@ module Mondrian
|
|
300
296
|
}
|
301
297
|
|
302
298
|
def members_to_mdx(members)
|
303
|
-
# if only one member which does not end with ]
|
299
|
+
# if only one member which does not end with ] or .Item(...)
|
304
300
|
# then assume it is expression which returns set
|
305
301
|
# TODO: maybe always include also single expressions in {...} to avoid some edge cases?
|
306
|
-
if members.length == 1 && members[0]
|
302
|
+
if members.length == 1 && members[0] !~ /(\]|\.Item\(\d+\))\z/i
|
307
303
|
members[0]
|
308
304
|
elsif members[0].is_a?(Symbol)
|
309
305
|
case members[0]
|
@@ -380,8 +376,9 @@ module Mondrian
|
|
380
376
|
end
|
381
377
|
|
382
378
|
def extract_dimension_name(full_name)
|
383
|
-
|
384
|
-
|
379
|
+
# "[Foo [Bar]]].[Baz]" => "Foo [Bar]"
|
380
|
+
if full_name
|
381
|
+
full_name.gsub(/\A\[|\]\z/, '').split('].[').first.try(:gsub, ']]', ']')
|
385
382
|
end
|
386
383
|
end
|
387
384
|
end
|
data/lib/mondrian/olap/result.rb
CHANGED
@@ -3,12 +3,14 @@ require 'bigdecimal'
|
|
3
3
|
module Mondrian
|
4
4
|
module OLAP
|
5
5
|
class Result
|
6
|
-
def initialize(connection, raw_cell_set)
|
6
|
+
def initialize(connection, raw_cell_set, options = {})
|
7
7
|
@connection = connection
|
8
8
|
@raw_cell_set = raw_cell_set
|
9
|
+
@profiling_handler = options[:profiling_handler]
|
10
|
+
@total_duration = options[:total_duration]
|
9
11
|
end
|
10
12
|
|
11
|
-
attr_reader :raw_cell_set
|
13
|
+
attr_reader :raw_cell_set, :profiling_handler, :total_duration
|
12
14
|
|
13
15
|
def axes_count
|
14
16
|
axes.length
|
@@ -105,6 +107,32 @@ module Mondrian
|
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
110
|
+
def profiling_plan
|
111
|
+
if profiling_handler
|
112
|
+
@raw_cell_set.close
|
113
|
+
if plan = profiling_handler.plan
|
114
|
+
plan.gsub("\r\n", "\n")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def profiling_timing
|
120
|
+
if profiling_handler
|
121
|
+
@raw_cell_set.close
|
122
|
+
profiling_handler.timing
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def profiling_mark_full(name, duration)
|
127
|
+
profiling_timing && profiling_timing.markFull(name, duration)
|
128
|
+
end
|
129
|
+
|
130
|
+
def profiling_timing_string
|
131
|
+
if profiling_timing && (timing_string = profiling_timing.toString)
|
132
|
+
timing_string.gsub("\r\n", "\n")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
108
136
|
# Specify drill through cell position, for example, as
|
109
137
|
# :row => 0, :cell => 1
|
110
138
|
# Specify max returned rows with :max_rows parameter
|
@@ -177,7 +205,7 @@ module Mondrian
|
|
177
205
|
if @raw_result_set.next
|
178
206
|
row_values = []
|
179
207
|
column_types.each_with_index do |column_type, i|
|
180
|
-
row_values << Result.java_to_ruby_value(@raw_result_set.getObject(i+1), column_type)
|
208
|
+
row_values << Result.java_to_ruby_value(@raw_result_set.getObject(i + 1), column_type)
|
181
209
|
end
|
182
210
|
row_values
|
183
211
|
else
|
@@ -248,24 +276,28 @@ module Mondrian
|
|
248
276
|
sql_non_extended = rolap_cell.getDrillThroughSQL(return_expressions, false)
|
249
277
|
sql_extended = rolap_cell.getDrillThroughSQL(return_expressions, true)
|
250
278
|
|
251
|
-
if sql_non_extended =~ /\Aselect (.*) from (.*) where (.*) order by (.*)\Z/
|
279
|
+
if sql_non_extended =~ /\Aselect (.*) from (.*) where (.*) order by (.*)\Z/m
|
280
|
+
non_extended_from = $2
|
281
|
+
non_extended_where = $3
|
282
|
+
# the latest Mondrian version sometimes returns sql_non_extended without order by
|
283
|
+
elsif sql_non_extended =~ /\Aselect (.*) from (.*) where (.*)\Z/m
|
252
284
|
non_extended_from = $2
|
253
285
|
non_extended_where = $3
|
254
286
|
# if drill through total measure with just all members selection
|
255
|
-
elsif sql_non_extended =~ /\Aselect (.*) from (.*)\Z/
|
287
|
+
elsif sql_non_extended =~ /\Aselect (.*) from (.*)\Z/m
|
256
288
|
non_extended_from = $2
|
257
289
|
non_extended_where = "1 = 1" # dummy true condition
|
258
290
|
else
|
259
291
|
raise ArgumentError, "cannot parse drill through SQL: #{sql_non_extended}"
|
260
292
|
end
|
261
293
|
|
262
|
-
if sql_extended =~ /\Aselect (.*) from (.*) where (.*) order by (.*)\Z/
|
294
|
+
if sql_extended =~ /\Aselect (.*) from (.*) where (.*) order by (.*)\Z/m
|
263
295
|
extended_select = $1
|
264
296
|
extended_from = $2
|
265
297
|
extended_where = $3
|
266
298
|
extended_order_by = $4
|
267
299
|
# if only measures are selected then there will be no order by
|
268
|
-
elsif sql_extended =~ /\Aselect (.*) from (.*) where (.*)\Z/
|
300
|
+
elsif sql_extended =~ /\Aselect (.*) from (.*) where (.*)\Z/m
|
269
301
|
extended_select = $1
|
270
302
|
extended_from = $2
|
271
303
|
extended_where = $3
|
@@ -282,13 +314,14 @@ module Mondrian
|
|
282
314
|
|
283
315
|
return_fields.size.times do |i|
|
284
316
|
column_alias = return_fields[i][:column_alias]
|
285
|
-
new_select_columns <<
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
317
|
+
new_select_columns <<
|
318
|
+
if column_expression = return_fields[i][:column_expression]
|
319
|
+
new_order_by_columns << column_expression
|
320
|
+
new_group_by_columns << column_expression if group_by && return_fields[i][:type] != :measure
|
321
|
+
"#{column_expression} AS #{column_alias}"
|
322
|
+
else
|
323
|
+
"'' AS #{column_alias}"
|
324
|
+
end
|
292
325
|
end
|
293
326
|
|
294
327
|
new_select = new_select_columns.join(', ')
|
@@ -361,7 +394,7 @@ module Mondrian
|
|
361
394
|
end
|
362
395
|
end
|
363
396
|
|
364
|
-
return_fields.size.times do |
|
397
|
+
return_fields.size.times do |i|
|
365
398
|
member_full_name = return_fields[i][:member_full_name]
|
366
399
|
begin
|
367
400
|
segment_list = Java::MondrianOlap::Util.parseIdentifier(member_full_name)
|
@@ -381,34 +414,34 @@ module Mondrian
|
|
381
414
|
end
|
382
415
|
|
383
416
|
return_fields[i][:column_expression] = case return_fields[i][:type]
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
end
|
417
|
+
when :name
|
418
|
+
if level_or_member.respond_to? :getNameExp
|
419
|
+
level_or_member.getNameExp.getExpression sql_query
|
420
|
+
end
|
421
|
+
when :property
|
422
|
+
if property = level_or_member.getProperties.to_a.detect{|p| p.getName == return_fields[i][:name]}
|
423
|
+
# property.getExp is a protected method therefore
|
424
|
+
# use a workaround to get the value from the field
|
425
|
+
f = property.java_class.declared_field("exp")
|
426
|
+
f.accessible = true
|
427
|
+
if column = f.value(property)
|
428
|
+
column.getExpression sql_query
|
397
429
|
end
|
430
|
+
end
|
431
|
+
else
|
432
|
+
if level_or_member.respond_to? :getKeyExp
|
433
|
+
return_fields[i][:type] = :key
|
434
|
+
level_or_member.getKeyExp.getExpression sql_query
|
398
435
|
else
|
399
|
-
|
400
|
-
|
401
|
-
|
436
|
+
return_fields[i][:type] = :measure
|
437
|
+
column_expression = level_or_member.getMondrianDefExpression.getExpression sql_query
|
438
|
+
if params[:group_by]
|
439
|
+
level_or_member.getAggregator.getExpression column_expression
|
402
440
|
else
|
403
|
-
|
404
|
-
column_expression = level_or_member.getMondrianDefExpression.getExpression sql_query
|
405
|
-
if params[:group_by]
|
406
|
-
level_or_member.getAggregator.getExpression column_expression
|
407
|
-
else
|
408
|
-
column_expression
|
409
|
-
end
|
441
|
+
column_expression
|
410
442
|
end
|
411
443
|
end
|
444
|
+
end
|
412
445
|
|
413
446
|
column_alias = if return_fields[i][:type] == :key
|
414
447
|
"#{return_fields[i][:name]} (Key)"
|
@@ -479,7 +512,7 @@ module Mondrian
|
|
479
512
|
@axes ||= @raw_cell_set.getAxes
|
480
513
|
end
|
481
514
|
|
482
|
-
def axis_positions(map_method, join_with=false)
|
515
|
+
def axis_positions(map_method, join_with = false)
|
483
516
|
axes.map do |axis|
|
484
517
|
axis.getPositions.map do |position|
|
485
518
|
names = position.getMembers.map do |member|
|
@@ -508,7 +541,7 @@ module Mondrian
|
|
508
541
|
:chapters => 4
|
509
542
|
}.freeze
|
510
543
|
|
511
|
-
def recursive_values(value_method, axes_sequence, current_index, cell_params=[])
|
544
|
+
def recursive_values(value_method, axes_sequence, current_index, cell_params = [])
|
512
545
|
if axis_number = axes_sequence[current_index]
|
513
546
|
axis_number = AXIS_SYMBOL_TO_NUMBER[axis_number] if axis_number.is_a?(Symbol)
|
514
547
|
positions_size = axes[axis_number].getPositions.size
|
data/lib/mondrian/olap/schema.rb
CHANGED
@@ -67,14 +67,30 @@ module Mondrian
|
|
67
67
|
attr_reader pluralize(name).to_sym
|
68
68
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
69
69
|
def #{name}(name=nil, attributes = {}, &block)
|
70
|
-
|
70
|
+
new_element = Schema::#{camel_case(name)}.new(name, attributes, self, &block)
|
71
|
+
@#{pluralize(name)} << new_element
|
72
|
+
new_element
|
71
73
|
end
|
72
74
|
RUBY
|
75
|
+
if name == :annotations
|
76
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
77
|
+
def annotations_hash
|
78
|
+
hash = {}
|
79
|
+
@annotationss.each do |annotations|
|
80
|
+
annotations.annotations.each do |annotation|
|
81
|
+
hash[annotation.name] = annotation.content
|
82
|
+
end
|
83
|
+
end
|
84
|
+
hash
|
85
|
+
end
|
86
|
+
RUBY
|
87
|
+
end
|
73
88
|
end
|
74
89
|
end
|
75
90
|
|
76
|
-
def self.content(type=nil)
|
91
|
+
def self.content(type = nil)
|
77
92
|
return @content if type.nil?
|
93
|
+
attr_reader :content
|
78
94
|
@content = type
|
79
95
|
end
|
80
96
|
|
@@ -86,7 +102,7 @@ module Mondrian
|
|
86
102
|
@xml_fragments << string
|
87
103
|
end
|
88
104
|
|
89
|
-
def to_xml(options={})
|
105
|
+
def to_xml(options = {})
|
90
106
|
options[:upcase_data_dictionary] = @upcase_data_dictionary unless @upcase_data_dictionary.nil?
|
91
107
|
Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
92
108
|
add_to_xml(xml, options)
|
@@ -125,7 +141,7 @@ module Mondrian
|
|
125
141
|
def xmlized_attributes(options)
|
126
142
|
# data dictionary values should be in uppercase if schema defined with :upcase_data_dictionary => true
|
127
143
|
# or by default when using Oracle or LucidDB driver (can be overridden by :upcase_data_dictionary => false)
|
128
|
-
upcase_attributes = if options[:upcase_data_dictionary].nil? && %w(oracle luciddb).include?(options[:driver]) ||
|
144
|
+
upcase_attributes = if options[:upcase_data_dictionary].nil? && %w(oracle luciddb snowflake).include?(options[:driver]) ||
|
129
145
|
options[:upcase_data_dictionary]
|
130
146
|
self.class.data_dictionary_names
|
131
147
|
else
|
@@ -17,7 +17,7 @@ module Mondrian
|
|
17
17
|
|
18
18
|
def coffeescript_function(arguments_string, text)
|
19
19
|
# construct function to ensure that last expression is returned
|
20
|
-
coffee_text = "#{arguments_string} ->\n" << text.gsub(/^/,' ')
|
20
|
+
coffee_text = "#{arguments_string} ->\n" << text.gsub(/^/, ' ')
|
21
21
|
javascript_text = CoffeeScript.compile(coffee_text, :bare => true)
|
22
22
|
# remove function definition first and last lines
|
23
23
|
javascript_text = javascript_text.strip.lines.to_a[1..-2].join
|
@@ -67,7 +67,7 @@ module Mondrian
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def ruby_formatter_java_class_name(name)
|
70
|
-
"rubyobj.#{self.class.name.gsub('::','.')}.#{ruby_formatter_name_to_class_name(name)}"
|
70
|
+
"rubyobj.#{self.class.name.gsub('::', '.')}.#{ruby_formatter_name_to_class_name(name)}"
|
71
71
|
end
|
72
72
|
|
73
73
|
end
|
@@ -180,19 +180,21 @@ JS
|
|
180
180
|
add_method_signature("getSyntax", [Java::mondrian.olap.Syntax])
|
181
181
|
|
182
182
|
UDF_SCALAR_TYPES = {
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
183
|
+
'Numeric' => Java::mondrian.olap.type.NumericType,
|
184
|
+
'String' => Java::mondrian.olap.type.StringType,
|
185
|
+
'Boolean' => Java::mondrian.olap.type.BooleanType,
|
186
|
+
'DateTime' => Java::mondrian.olap.type.DateTimeType,
|
187
|
+
'Decimal' => Java::mondrian.olap.type.DecimalType,
|
188
|
+
'Scalar' => Java::mondrian.olap.type.ScalarType
|
189
189
|
}
|
190
190
|
UDF_OTHER_TYPES = {
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
191
|
+
'Member' => Java::mondrian.olap.type.MemberType::Unknown,
|
192
|
+
'Tuple' => Java::mondrian.olap.type.TupleType.new([].to_java(Java::mondrian.olap.type.Type)),
|
193
|
+
'Hierarchy' => Java::mondrian.olap.type.HierarchyType.new(nil, nil),
|
194
|
+
'Level' => Java::mondrian.olap.type.LevelType::Unknown
|
195
195
|
}
|
196
|
+
UDF_OTHER_TYPES['Set'] = UDF_OTHER_TYPES['MemberSet'] = Java::mondrian.olap.type.SetType.new(UDF_OTHER_TYPES['Member'])
|
197
|
+
UDF_OTHER_TYPES['TupleSet'] = Java::mondrian.olap.type.SetType.new(UDF_OTHER_TYPES['Tuple'])
|
196
198
|
|
197
199
|
def getParameterTypes
|
198
200
|
@parameterTypes ||= self.class.parameters.map{|p| get_java_type(p)}
|
@@ -214,7 +216,7 @@ JS
|
|
214
216
|
|
215
217
|
def execute(evaluator, arguments)
|
216
218
|
values = []
|
217
|
-
self.class.parameters.each_with_index do |p,i|
|
219
|
+
self.class.parameters.each_with_index do |p, i|
|
218
220
|
value = UDF_SCALAR_TYPES[p] ? arguments[i].evaluateScalar(evaluator) : arguments[i].evaluate(evaluator)
|
219
221
|
values << value
|
220
222
|
end
|
@@ -239,9 +241,12 @@ JS
|
|
239
241
|
end
|
240
242
|
|
241
243
|
def self.stringified_type(type)
|
242
|
-
|
243
|
-
|
244
|
-
|
244
|
+
type_as_string = stringify(type)
|
245
|
+
if UDF_SCALAR_TYPES[type_as_string] || UDF_OTHER_TYPES[type_as_string]
|
246
|
+
type_as_string
|
247
|
+
else
|
248
|
+
raise ArgumentError, "Invalid user defined function type #{type.inspect}"
|
249
|
+
end
|
245
250
|
end
|
246
251
|
|
247
252
|
def self.stringify(arg)
|
@@ -4,15 +4,21 @@ describe "Connection role" do
|
|
4
4
|
|
5
5
|
describe "create connection" do
|
6
6
|
before(:each) do
|
7
|
-
@
|
8
|
-
|
7
|
+
@all_roles = [
|
8
|
+
@role_name = role_name = 'California manager',
|
9
|
+
@role_name2 = role_name2 = 'Dummy, with comma',
|
10
|
+
@simple_role_name = simple_role_name = 'USA manager',
|
11
|
+
@union_role_name = union_role_name = 'Union California manager',
|
12
|
+
@intermediate_union_role_name = intermediate_union_role_name = "Intermediate #{union_role_name}"
|
13
|
+
]
|
14
|
+
|
9
15
|
@schema = Mondrian::OLAP::Schema.define do
|
10
16
|
cube 'Sales' do
|
11
17
|
table 'sales'
|
12
18
|
dimension 'Gender', :foreign_key => 'customer_id' do
|
13
19
|
hierarchy :has_all => true, :primary_key => 'id' do
|
14
20
|
table 'customers'
|
15
|
-
level 'Gender', :column => 'gender', :unique_members => true
|
21
|
+
level 'Gender', :column => 'gender', :unique_members => true, :hide_member_if => 'IfBlankName'
|
16
22
|
end
|
17
23
|
end
|
18
24
|
dimension 'Customers', :foreign_key => 'customer_id' do
|
@@ -49,6 +55,26 @@ describe "Connection role" do
|
|
49
55
|
end
|
50
56
|
role role_name2
|
51
57
|
|
58
|
+
role simple_role_name do
|
59
|
+
schema_grant :access => 'none' do
|
60
|
+
cube_grant :cube => 'Sales', :access => 'all' do
|
61
|
+
hierarchy_grant :hierarchy => '[Customers]', :access => 'custom', :bottom_level => '[Customers].[State Province]' do
|
62
|
+
member_grant :member => '[Customers].[USA]', :access => 'all'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
role intermediate_union_role_name do
|
68
|
+
union do
|
69
|
+
role_usage role_name: simple_role_name
|
70
|
+
end
|
71
|
+
end
|
72
|
+
role union_role_name do
|
73
|
+
union do
|
74
|
+
role_usage role_name: intermediate_union_role_name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
52
78
|
# to test that Role elements are generated before UserDefinedFunction
|
53
79
|
user_defined_function 'Factorial' do
|
54
80
|
ruby do
|
@@ -63,12 +89,16 @@ describe "Connection role" do
|
|
63
89
|
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
64
90
|
end
|
65
91
|
|
92
|
+
after(:each) do
|
93
|
+
@olap.role_name = nil if @olap
|
94
|
+
end
|
95
|
+
|
66
96
|
it "should connect" do
|
67
97
|
@olap.should be_connected
|
68
98
|
end
|
69
99
|
|
70
100
|
it "should get available role names" do
|
71
|
-
@olap.available_role_names.should ==
|
101
|
+
@olap.available_role_names.sort.should == @all_roles.sort
|
72
102
|
end
|
73
103
|
|
74
104
|
it "should not get role name if not set" do
|
@@ -113,17 +143,40 @@ describe "Connection role" do
|
|
113
143
|
# end
|
114
144
|
|
115
145
|
it "should not get non-visible member when role name set in connection parameters" do
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
@cube.member('[Customers].[USA].[CA].[Los Angeles]').should be_nil
|
146
|
+
olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge schema: @schema, role: @role_name)
|
147
|
+
cube = olap.cube('Sales')
|
148
|
+
cube.member('[Customers].[USA].[CA].[Los Angeles]').should be_nil
|
120
149
|
end
|
121
150
|
|
122
151
|
it "should not get non-visible member when several role names set in connection parameters" do
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
152
|
+
olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge schema: @schema, roles: [@role_name, @role_name2])
|
153
|
+
cube = olap.cube('Sales')
|
154
|
+
cube.member('[Customers].[USA].[CA].[Los Angeles]').should be_nil
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should see members from ragged dimensions when using single role" do
|
158
|
+
# Workaround for a Mondrian bug which does not allow access to ragged dimensions when using single role.
|
159
|
+
# This syntax will create a union role with one role.
|
160
|
+
@olap.role_names = [@role_name]
|
161
|
+
cube = @olap.cube('Sales')
|
162
|
+
cube.member('[Customers].[USA].[CA].[Los Angeles]').should be_nil
|
163
|
+
cube.member('[Gender].[All Genders]').should_not be_nil
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should see members from ragged dimensions when using multiple roles" do
|
167
|
+
@olap.role_names = [@role_name, @role_name2]
|
168
|
+
cube = @olap.cube('Sales')
|
169
|
+
cube.member('[Customers].[USA].[CA].[Los Angeles]').should be_nil
|
170
|
+
cube.member('[Gender].[All Genders]').should_not be_nil
|
171
|
+
end
|
172
|
+
|
173
|
+
# Test patch for UnionRoleImpl getBottomLevelDepth method
|
174
|
+
it "should see member as drillable when using union of union role" do
|
175
|
+
@olap.role_names = [@union_role_name]
|
176
|
+
cube = @olap.cube('Sales')
|
177
|
+
cube.member('[Customers].[All Customers]').should be_drillable
|
178
|
+
cube.member('[Customers].[All Customers].[USA]').should be_drillable
|
179
|
+
cube.member('[Customers].[All Customers].[USA].[CA]').should_not be_drillable
|
127
180
|
end
|
128
181
|
|
129
182
|
end
|