mondrian-rest 0.6.0-java → 0.7.0-java

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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/README.md +2 -0
  4. data/Rakefile +6 -1
  5. data/lib/jars/com/codepoetics/protonpack/1.9/protonpack-1.9.jar +0 -0
  6. data/lib/jars/com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar +0 -0
  7. data/lib/jars/com/fasterxml/jackson/core/jackson-core/2.8.5/jackson-core-2.8.5.jar +0 -0
  8. data/lib/jars/com/fasterxml/jackson/core/jackson-databind/2.8.5/jackson-databind-2.8.5.jar +0 -0
  9. data/lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-guava/2.8.5/jackson-datatype-guava-2.8.5.jar +0 -0
  10. data/lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.8.5/jackson-datatype-jdk8-2.8.5.jar +0 -0
  11. data/lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.8.5/jackson-datatype-jsr310-2.8.5.jar +0 -0
  12. data/lib/jars/com/google/guava/guava/19.0/guava-19.0.jar +0 -0
  13. data/lib/jars/me/yanaga/guava-stream/1.0/guava-stream-1.0.jar +0 -0
  14. data/lib/jars/mondrian-rest_jars.rb +28 -0
  15. data/lib/jars/no/ssb/jsonstat/json-stat-java/0.2.2/json-stat-java-0.2.2.jar +0 -0
  16. data/lib/mondrian_rest/api.rb +60 -45
  17. data/lib/mondrian_rest/api_formatters.rb +6 -76
  18. data/lib/mondrian_rest/api_helpers.rb +14 -0
  19. data/lib/mondrian_rest/formatters/aggregation_json.rb +10 -0
  20. data/lib/mondrian_rest/formatters/csv.rb +21 -0
  21. data/lib/mondrian_rest/formatters/excel.rb +30 -0
  22. data/lib/mondrian_rest/formatters/jsonrecords.rb +31 -0
  23. data/lib/mondrian_rest/formatters/jsonstat.rb +50 -0
  24. data/lib/mondrian_rest/mondrian_ext.rb +12 -3
  25. data/lib/mondrian_rest/query_helper.rb +8 -3
  26. data/lib/mondrian_rest.rb +2 -0
  27. data/mondrian-rest.gemspec +6 -3
  28. metadata +37 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2710889190b4d58cd7592415468caf4b7f5b7b95
4
- data.tar.gz: 79bfcad96399941a47c1ba2e553e466209b053af
3
+ metadata.gz: 9884ded4baf72e8778db0f38bd66689a098ba4c1
4
+ data.tar.gz: 41004cd22953933eb63c74f335c2ee55b9dfea1b
5
5
  SHA512:
6
- metadata.gz: 81b615aa3796ac61ddd850dec37bfbcecd75a5565b3de5fad18acea59f212dae2445b2c4434d6d1910e9a5b433045cd46ef6d163b9182b314841b8d285006e1d
7
- data.tar.gz: 6bbed693f2ba708a44688b9d85b0980afe343c52d7d9da2f26259e10d554b94b53e4abe88c89d77b2c39be453c6f532cb4dae2bf330e2ba0290f541d9c4beecf
6
+ metadata.gz: 7af0aa6def1e41782c5b517cef5199545a0be1f69baff8400499b5d5f1231f3f5a93d2bfec6a5c8f6f98c83c421ebada332b5e798a8104158721a7430a38ba7f
7
+ data.tar.gz: 8280d75f3484daba329486853a32aa306ec6b3935511345ad3887405de0b50c1879470e26e4aa2ded4d57426a9744c4cb84aab6d4cf945189294869cd2d0afa2
data/.travis.yml CHANGED
@@ -1,4 +1,6 @@
1
1
  language: ruby
2
+ jdk:
3
+ - oraclejdk8
2
4
  rvm:
3
5
  - jruby-9.1.5.0
4
6
  env:
data/README.md CHANGED
@@ -8,6 +8,8 @@ See [`mondrian-rest-demo`](https://github.com/jazzido/mondrian-rest-demo) and [`
8
8
 
9
9
  [`mondrian-rest-ui`](https://github.com/jazzido/mondrian-rest-ui) is an experimental visualization tool for `mondrian-rest`, inspired by [CubesViewer](https://github.com/jjmontesl/cubesviewer) and [Polestar](https://github.com/vega/polestar).
10
10
 
11
+ *NOTE*: `mondrian-rest` expect the `mondrian.olap.SsasCompatibleNaming` Java property is set to `true`. Set a environment variable `JAVA_OPTS="-Dmondrian.olap.SsasCompatibleNaming=true""` to the process that uses `mondrian-rest`.
12
+
11
13
  ## Credits
12
14
 
13
15
  Initial inspiration for this project came from [Stefan Urbanek](https://github.com/Stiivi)'s [`cubes`](http://cubes.databrewery.org/) OLAP server. `mondrian-rest` uses [Raimonds Simanovskis](https://github.com/rsim)'s fantastic [`mondrian-olap`](https://github.com/rsim/mondrian-olap) library.
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require "rspec/core/rake_task"
2
+ require 'jars/installer'
2
3
 
3
- require_relative './lib/mondrian_rest.rb'
4
4
 
5
5
  desc "Run specs"
6
6
  RSpec::Core::RakeTask.new(:spec)
@@ -11,6 +11,7 @@ end
11
11
 
12
12
  desc "API Routes"
13
13
  task :routes do
14
+ require_relative './lib/mondrian_rest.rb'
14
15
  Mondrian::REST::Api.routes.each do |api|
15
16
  method = api.route_method.ljust(10)
16
17
  path = api.route_path
@@ -18,4 +19,8 @@ task :routes do
18
19
  end
19
20
  end
20
21
 
22
+ task :install_jars do
23
+ Jars::Installer.vendor_jars!("lib/jars")
24
+ end
25
+
21
26
  task :default => [:spec]
@@ -0,0 +1,28 @@
1
+ # this is a generated file, to avoid over-writing it just delete this comment
2
+ begin
3
+ require 'jar_dependencies'
4
+ rescue LoadError
5
+ require 'com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.8.5/jackson-datatype-jdk8-2.8.5.jar'
6
+ require 'com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar'
7
+ require 'me/yanaga/guava-stream/1.0/guava-stream-1.0.jar'
8
+ require 'com/fasterxml/jackson/core/jackson-databind/2.8.5/jackson-databind-2.8.5.jar'
9
+ require 'no/ssb/jsonstat/json-stat-java/0.2.2/json-stat-java-0.2.2.jar'
10
+ require 'com/fasterxml/jackson/core/jackson-core/2.8.5/jackson-core-2.8.5.jar'
11
+ require 'com/fasterxml/jackson/datatype/jackson-datatype-guava/2.8.5/jackson-datatype-guava-2.8.5.jar'
12
+ require 'com/google/guava/guava/19.0/guava-19.0.jar'
13
+ require 'com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.8.5/jackson-datatype-jsr310-2.8.5.jar'
14
+ require 'com/codepoetics/protonpack/1.9/protonpack-1.9.jar'
15
+ end
16
+
17
+ if defined? Jars
18
+ require_jar( 'com.fasterxml.jackson.datatype', 'jackson-datatype-jdk8', '2.8.5' )
19
+ require_jar( 'com.fasterxml.jackson.core', 'jackson-annotations', '2.8.0' )
20
+ require_jar( 'me.yanaga', 'guava-stream', '1.0' )
21
+ require_jar( 'com.fasterxml.jackson.core', 'jackson-databind', '2.8.5' )
22
+ require_jar( 'no.ssb.jsonstat', 'json-stat-java', '0.2.2' )
23
+ require_jar( 'com.fasterxml.jackson.core', 'jackson-core', '2.8.5' )
24
+ require_jar( 'com.fasterxml.jackson.datatype', 'jackson-datatype-guava', '2.8.5' )
25
+ require_jar( 'com.google.guava', 'guava', '19.0' )
26
+ require_jar( 'com.fasterxml.jackson.datatype', 'jackson-datatype-jsr310', '2.8.5' )
27
+ require_jar( 'com.codepoetics', 'protonpack', '1.9' )
28
+ end
@@ -21,11 +21,16 @@ module Mondrian::REST
21
21
  resource :mdx do
22
22
  content_type :xls, "application/vnd.ms-excel"
23
23
  formatter :xls, Mondrian::REST::Formatters::XLS
24
+
24
25
  content_type :csv, "text/csv"
25
26
  formatter :csv, Mondrian::REST::Formatters::CSV
27
+
26
28
  content_type :json, "application/json"
27
29
  formatter :json, Mondrian::REST::Formatters::AggregationJSON
28
30
 
31
+ content_type :jsonrecords, "application/x-jsonrecords"
32
+ formatter :jsonrecords, Mondrian::REST::Formatters::JSONRecords
33
+
29
34
  desc "Execute an MDX query against a cube"
30
35
  content_type :txt, "text/plain"
31
36
  post do
@@ -37,22 +42,22 @@ module Mondrian::REST
37
42
  end
38
43
 
39
44
  resource :flush do
40
- params do
41
- requires :secret, type: String, desc: "Secret key"
42
- end
43
- content_type :json, "application/json"
44
- desc "Flush the schema cache"
45
+ params do
46
+ requires :secret, type: String, desc: "Secret key"
47
+ end
48
+ content_type :json, "application/json"
49
+ desc "Flush the schema cache"
45
50
 
46
- get do
47
- if ENV['MONDRIAN_REST_SECRET'].nil?
48
- error!("Please set MONDRIAN_REST_SECRET to use this endpoint", 403)
49
- end
50
- if params[:secret] != ENV['MONDRIAN_REST_SECRET']
51
- error!("Invalid secret key.", 403)
52
- end
53
- {
54
- 'status' => olap_flush
55
- }
51
+ get do
52
+ if ENV['MONDRIAN_REST_SECRET'].nil?
53
+ error!("Please set MONDRIAN_REST_SECRET to use this endpoint", 403)
54
+ end
55
+ if params[:secret] != ENV['MONDRIAN_REST_SECRET']
56
+ error!("Invalid secret key.", 403)
57
+ end
58
+ {
59
+ 'status' => olap_flush
60
+ }
56
61
  end
57
62
  end
58
63
 
@@ -78,25 +83,25 @@ module Mondrian::REST
78
83
  end
79
84
 
80
85
  resource :members do
81
- desc "return a member by its full name"
82
- params do
83
- requires :full_name,
84
- type: String,
85
- regexp: /[a-z0-9\.,\-\s%\[\]\(\)]+/i
86
- end
87
- get do
88
- member_full_name = URI.decode(params[:full_name])
86
+ desc "return a member by its full name"
87
+ params do
88
+ requires :full_name,
89
+ type: String,
90
+ regexp: /[a-z0-9\.,\-\s%\[\]\(\)]+/i
91
+ end
92
+ get do
93
+ member_full_name = URI.decode(params[:full_name])
89
94
 
90
- m = get_member(get_cube_or_404(params[:cube_name]),
91
- member_full_name)
92
- if m.nil?
93
- error!("Member `#{member_full_name}` not found in cube `#{params[:cube_name]}`", 404)
94
- end
95
- m.to_h.merge({
96
- ancestors: m.ancestors.map(&:to_h),
97
- dimension: m.dimension_info
98
- })
95
+ m = get_member(get_cube_or_404(params[:cube_name]),
96
+ member_full_name)
97
+ if m.nil?
98
+ error!("Member `#{member_full_name}` not found in cube `#{params[:cube_name]}`", 404)
99
99
  end
100
+ m.to_h.merge({
101
+ ancestors: m.ancestors.map(&:to_h),
102
+ dimension: m.dimension_info
103
+ })
104
+ end
100
105
  end
101
106
 
102
107
 
@@ -113,6 +118,9 @@ module Mondrian::REST
113
118
  content_type :jsonrecords, "application/x-jsonrecords"
114
119
  formatter :jsonrecords, Mondrian::REST::Formatters::JSONRecords
115
120
 
121
+ content_type :jsonstat, "application/x-jsonstat"
122
+ formatter :jsonstat, Mondrian::REST::Formatters::JSONStat
123
+
116
124
  rescue_from PropertyError do |e|
117
125
  error!({error: e}, 400)
118
126
  end
@@ -129,18 +137,13 @@ module Mondrian::REST
129
137
  optional :properties, type: Array, desc: "Include member properties"
130
138
  optional :caption, type: Array, desc: "Replace caption with property", default: []
131
139
  end
132
- get do
133
- cube = get_cube_or_404(params[:cube_name])
134
- query = build_query(cube, params)
135
- mdx_query = query.to_mdx
136
140
 
137
- result = mdx(query.to_mdx)
138
- result.mdx = mdx_query if params[:debug]
139
- result.properties = params[:properties]
140
- result.caption_properties = params[:caption]
141
- result.cube = cube
141
+ get do
142
+ run_from_params(params)
143
+ end
142
144
 
143
- result
145
+ post do
146
+ run_from_params(params)
144
147
  end
145
148
  end
146
149
 
@@ -164,6 +167,8 @@ module Mondrian::REST
164
167
 
165
168
  params do
166
169
  optional :member_properties, type: Array, default: []
170
+ optional :caption, type: String, desc: "Replace caption with property", default: nil
171
+ optional :children, type: Boolean, default: false
167
172
  end
168
173
 
169
174
  get do
@@ -179,13 +184,21 @@ module Mondrian::REST
179
184
  error!("level #{params[:level_name]} not found in dimension #{params[:dimension_name]}")
180
185
  end
181
186
 
182
- level.to_h(params[:member_properties])
187
+ level.to_h(params[:member_properties], params[:children], params[:caption])
183
188
  end
184
189
 
185
190
  route_param :member_key,
186
191
  type: String,
187
- requirements: { member_key: /[a-z0-9\.\-\s]+/i } do
192
+ requirements: { member_key: /[A-Za-z0-9\.\-\s%]+/i } do
193
+
194
+ params do
195
+ optional :caption, type: String, desc: "Replace caption with property", default: nil
196
+ optional :member_properties, type: Array, default: []
197
+ optional :children, type: Boolean, default: false
198
+ end
199
+
188
200
  get do
201
+ puts params.inspect
189
202
  cube = get_cube_or_404(params[:cube_name])
190
203
  dimension = cube.dimension(params[:dimension_name])
191
204
  level = dimension.hierarchies[0].level(params[:level_name])
@@ -194,7 +207,9 @@ module Mondrian::REST
194
207
  m.property_value('MEMBER_KEY').to_s == params[:member_key]
195
208
  }
196
209
  error!('member not found', 404) if member.nil?
197
- member.to_h.merge({ancestors: member.ancestors.map(&:to_h)})
210
+ member
211
+ .to_h(params[:member_properties], params[:caption], params[:children])
212
+ .merge({ancestors: member.ancestors.map(&:to_h)})
198
213
  end
199
214
  end
200
215
  end
@@ -1,81 +1,11 @@
1
- require 'csv'
2
- require 'writeexcel'
1
+ require_relative './formatters/aggregation_json'
2
+ require_relative './formatters/csv'
3
+ require_relative './formatters/excel'
4
+ require_relative './formatters/jsonrecords'
5
+ require_relative './formatters/jsonstat'
3
6
 
4
- module Mondrian::REST::Formatters
5
-
6
- module AggregationJSON
7
- def self.call(result, env)
8
- add_parents = env['rack.request.query_hash']['parents'] == 'true'
9
- debug = env['rack.request.query_hash']['debug'] == 'true'
10
-
11
- result.to_h(add_parents, debug).to_json
12
- end
13
- end
14
-
15
- module XLS
16
- def self.call(result, env)
17
- add_parents = env['rack.request.query_hash']['parents'] == 'true'
18
- debug = env['rack.request.query_hash']['debug'] == 'true'
19
- properties = env['rack.request.query_hash']['properties'] || []
20
-
21
- out = StringIO.new
22
- book = WriteExcel.new(out)
23
- sheet = book.add_worksheet
24
-
25
- Mondrian::REST::Formatters
26
- .tidy(result,
27
- add_parents: add_parents,
28
- debug: debug,
29
- properties: properties)
30
- .each_with_index do |row, i|
31
- row.each_with_index { |cell, j|
32
- sheet.write(i, j, cell)
33
- }
34
- end
35
-
36
- book.close
37
- out.string
38
- end
39
- end
40
7
 
41
- module CSV
42
- def self.call(result, env)
43
- add_parents = env['rack.request.query_hash']['parents'] == 'true'
44
- debug = env['rack.request.query_hash']['debug'] == 'true'
45
- properties = env['rack.request.query_hash']['properties'] || []
46
-
47
- rows = Mondrian::REST::Formatters.tidy(result,
48
- add_parents: add_parents,
49
- debug: debug,
50
- properties: properties)
51
-
52
- ::CSV.generate do |csv|
53
- rows.each { |row| csv << row }
54
- end
55
- end
56
- end
57
-
58
- module JSONRecords
59
- def self.call(result, env)
60
- add_parents = env['rack.request.query_hash']['parents'] == 'true'
61
- debug = env['rack.request.query_hash']['debug'] == 'true'
62
- properties = env['rack.request.query_hash']['properties'] || []
63
-
64
- rows = Mondrian::REST::Formatters.tidy(result,
65
- add_parents: add_parents,
66
- debug: debug,
67
- properties: properties).lazy
68
- keys = rows.next
69
-
70
- {
71
- data: rows.with_index.with_object([]) { |(row, i), data|
72
- next if i == 0
73
- data << Hash[keys.zip(row)]
74
- }
75
- }.to_json
76
-
77
- end
78
- end
8
+ module Mondrian::REST::Formatters
79
9
 
80
10
  ##
81
11
  # Generate 'tidy data' (http://vita.had.co.nz/papers/tidy-data.pdf)
@@ -50,6 +50,20 @@ module Mondrian::REST
50
50
  end
51
51
  end
52
52
 
53
+ def run_from_params(params)
54
+ cube = get_cube_or_404(params[:cube_name])
55
+ query = build_query(cube, params)
56
+ mdx_query = query.to_mdx
57
+
58
+ result = mdx(query.to_mdx)
59
+ result.mdx = mdx_query if params[:debug]
60
+ result.properties = params[:properties]
61
+ result.caption_properties = params[:caption]
62
+ result.cube = cube
63
+
64
+ result
65
+ end
66
+
53
67
  NEST = Mondrian::REST::Nest.new
54
68
  .key { |d| d[0] }
55
69
  .key { |d| d[1] }
@@ -0,0 +1,10 @@
1
+ module Mondrian::REST::Formatters
2
+ module AggregationJSON
3
+ def self.call(result, env)
4
+ add_parents = env['rack.request.query_hash']['parents'] == 'true'
5
+ debug = env['rack.request.query_hash']['debug'] == 'true'
6
+
7
+ result.to_h(add_parents, debug).to_json
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require 'csv'
2
+
3
+ module Mondrian::REST::Formatters
4
+ module CSV
5
+ def self.call(result, env)
6
+ qh = env['rack.request.query_hash']
7
+ add_parents = qh['parents'] == 'true'
8
+ debug = qh['debug'] == 'true'
9
+ properties = qh['properties'] || []
10
+
11
+ rows = Mondrian::REST::Formatters.tidy(result,
12
+ add_parents: add_parents,
13
+ debug: debug,
14
+ properties: properties)
15
+
16
+ ::CSV.generate do |csv|
17
+ rows.each { |row| csv << row }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require 'writeexcel'
2
+
3
+ module Mondrian::REST::Formatters
4
+ module XLS
5
+ def self.call(result, env)
6
+ qh = env['rack.request.query_hash']
7
+ add_parents = qh['parents'] == 'true'
8
+ debug = qh['debug'] == 'true'
9
+ properties = qh['properties'] || []
10
+
11
+ out = StringIO.new
12
+ book = WriteExcel.new(out)
13
+ sheet = book.add_worksheet
14
+
15
+ Mondrian::REST::Formatters
16
+ .tidy(result,
17
+ add_parents: add_parents,
18
+ debug: debug,
19
+ properties: properties)
20
+ .each_with_index do |row, i|
21
+ row.each_with_index { |cell, j|
22
+ sheet.write(i, j, cell)
23
+ }
24
+ end
25
+
26
+ book.close
27
+ out.string
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module Mondrian::REST::Formatters
2
+ module JSONRecords
3
+ def self.call(result, env)
4
+ qh = env['rack.request.query_hash']
5
+ add_parents = qh['parents'] == 'true'
6
+ debug = qh['debug'] == 'true'
7
+ properties = qh['properties'] || []
8
+ format = qh['format'] == 'array' ? 'array' : 'object'
9
+
10
+ rows = Mondrian::REST::Formatters.tidy(result,
11
+ add_parents: add_parents,
12
+ debug: debug,
13
+ properties: properties).lazy
14
+ keys = rows.first
15
+
16
+ if format == 'array'
17
+ {
18
+ variables: keys,
19
+ data: rows.drop(1).to_a
20
+ }.to_json
21
+ else
22
+ {
23
+ data: rows.with_index.with_object([]) { |(row, i), data|
24
+ next if i == 0
25
+ data << Hash[keys.zip(row)]
26
+ }
27
+ }.to_json
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ require 'java'
2
+
3
+ module Mondrian::REST::Formatters
4
+ module JSONStat
5
+
6
+ def self.call(result, env)
7
+
8
+ mapper = Java::ComFasterxmlJacksonDatabind::ObjectMapper.new
9
+ mapper.registerModule(Java::NoSsbJsonstat::JsonStatModule.new)
10
+ mapper.registerModule(Java::ComFasterxmlJacksonDatatypeJdk8::Jdk8Module.new.configureAbsentsAsNulls(true))
11
+ mapper.setSerializationInclusion(Java::ComFasterxmlJacksonAnnotation::JsonInclude::Include::NON_NULL)
12
+ mapper.registerModule(Java::ComFasterxmlJacksonDatatypeGuava::GuavaModule.new.configureAbsentsAsNulls(false))
13
+
14
+ rs = result.to_h
15
+ rdims = rs[:axis_dimensions].reverse
16
+
17
+ builder = Java::NoSsbJsonstatV2::Dataset
18
+ .create
19
+ .withLabel('Aggregation: ')
20
+ .withSource(env['REQUEST_URI'] || '')
21
+
22
+ dimensions = rdims.map.with_index do |d, i|
23
+ dim = Java::NoSsbJsonstatV2::Dimension
24
+ .create(d[:name])
25
+
26
+ if d[:type] == :measures
27
+ dim = dim.withMetricRole
28
+ elsif d[:type] == :time
29
+ dim = dim.withTimeRole
30
+ end
31
+
32
+ dim.withLabel(d[:caption])
33
+ .withIndexedLabels(
34
+ Java::ComGoogleCommonCollect::ImmutableMap.copyOf(
35
+ Hash[*(rs[:axes][-1 - i][:members].map { |m| [ m[:key].to_s, m[:caption] ] }.flatten)].to_java
36
+ )
37
+ )
38
+ end
39
+
40
+ dataset = builder
41
+ .withDimensions(dimensions)
42
+ .withValues(rs[:values].flatten)
43
+ .build
44
+
45
+ mapper.writeValueAsString(dataset)
46
+
47
+ end
48
+
49
+ end
50
+ end
@@ -102,6 +102,10 @@ module Mondrian
102
102
  end
103
103
  end
104
104
 
105
+ class Hierarchy
106
+ attr_reader :dimension
107
+ end
108
+
105
109
  INTERNAL_PROPS = Set.new(['CATALOG_NAME', 'SCHEMA_NAME', 'CUBE_NAME', 'DIMENSION_UNIQUE_NAME', 'HIERARCHY_UNIQUE_NAME', 'LEVEL_UNIQUE_NAME', 'LEVEL_NUMBER', 'MEMBER_ORDINAL', 'MEMBER_NAME', 'MEMBER_UNIQUE_NAME', 'MEMBER_TYPE', 'MEMBER_GUID', 'MEMBER_CAPTION', 'CHILDREN_CARDINALITY', 'PARENT_LEVEL', 'PARENT_UNIQUE_NAME', 'PARENT_COUNT', 'DESCRIPTION', '$visible', 'MEMBER_KEY', 'IS_PLACEHOLDERMEMBER', 'IS_DATAMEMBER', 'DEPTH', 'DISPLAY_INFO', 'VALUE', '$scenario', 'CELL_FORMATTER', 'CELL_FORMATTER_SCRIPT', 'CELL_FORMATTER_SCRIPT_LANGUAGE', 'DISPLAY_FOLDER', 'FORMAT_EXP', 'KEY', '$name']).freeze
106
110
 
107
111
  class Level
@@ -111,13 +115,17 @@ module Mondrian
111
115
  @full_name ||= @raw_level.getUniqueName
112
116
  end
113
117
 
114
- def to_h(member_properties=[])
118
+ def unique_name
119
+ "#{Java::MondrianOlap::Util.quoteMdxIdentifier(hierarchy.dimension.name)}.#{Java::MondrianOlap::Util.quoteMdxIdentifier(hierarchy.name)}.#{Java::MondrianOlap::Util.quoteMdxIdentifier(self.name)}"
120
+ end
121
+
122
+ def to_h(member_properties=[], get_children=false, member_caption=nil)
115
123
  {
116
124
  name: self.name,
117
125
  caption: self.caption,
118
126
  members: self.members
119
127
  .uniq { |m| m.property_value('MEMBER_KEY') }
120
- .map { |m| m.to_h(member_properties) },
128
+ .map { |m| m.to_h(member_properties, member_caption, get_children) },
121
129
  :properties => self.own_props.map { |p|
122
130
  p.getName
123
131
  }
@@ -140,7 +148,7 @@ module Mondrian
140
148
  @raw_member.getLevel
141
149
  end
142
150
 
143
- def to_h(properties=[], caption_property=nil)
151
+ def to_h(properties=[], caption_property=nil, get_children=false)
144
152
  kv = [:name, :full_name, :all_member?,
145
153
  :drillable?, :depth].map { |m|
146
154
  [m, self.send(m)]
@@ -150,6 +158,7 @@ module Mondrian
150
158
  kv << [:num_children, self.property_value('CHILDREN_CARDINALITY')]
151
159
  kv << [:parent_name, self.property_value('PARENT_UNIQUE_NAME')]
152
160
  kv << [:level_name, self.raw_level.name]
161
+ kv << [:children, get_children ? self.children.map { |c| c.to_h([], nil, get_children)} : []]
153
162
 
154
163
  if properties.size > 0
155
164
  kv << [
@@ -39,6 +39,11 @@ module Mondrian::REST
39
39
  set_members = p.getArgList.map { |id_node|
40
40
  get_member(cube, unparse_node(id_node))
41
41
  }
42
+
43
+ if set_members.any? { |m| m.nil? }
44
+ error!("Illegal cut. Unknown member in cut set", 400)
45
+ end
46
+
42
47
  ls = set_members.map(&:raw_level).uniq
43
48
  unless ls.size == 1
44
49
  error!("Illegal cut: " + cut_expr, 400)
@@ -107,7 +112,7 @@ module Mondrian::REST
107
112
 
108
113
  if s.size > 1
109
114
  if s.size == 3 # 3 parts, means that a hierarchy was provided
110
- hierarchy = dimension.hierarchies.find { |h_| h_.name == "#{dimension.name}.#{s[1].name}" }
115
+ hierarchy = dimension.hierarchies.find { |h_| h_.name == s[1].name }
111
116
  if hierarchy.nil?
112
117
  error!("Hierarchy `#{s[1].name}` does not exist in dimension #{dimension.name}", 404)
113
118
  end
@@ -136,7 +141,7 @@ module Mondrian::REST
136
141
  cm_names = measure_members.map(&:name)
137
142
 
138
143
  options['measures'].each { |m|
139
- error!("Measure #{m} does not exist in cube #{cube.name}", 404) unless cm_names.include?(m)
144
+ error!("Measure #{m} does not exist in cube #{cube.name}", 400) unless cm_names.include?(m)
140
145
  }
141
146
 
142
147
  # measures go in axis(0) of the resultset
@@ -190,7 +195,7 @@ module Mondrian::REST
190
195
  raise "Unsupported operation"
191
196
  end
192
197
  else
193
- qa.raw_level.unique_name + '.Members'
198
+ qa.unique_name + '.Members'
194
199
  end
195
200
  end
196
201
 
data/lib/mondrian_rest.rb CHANGED
@@ -2,6 +2,8 @@ require 'json'
2
2
 
3
3
  Java::JavaLang::System.setProperty("jdbc.driver.autoload", "true")
4
4
 
5
+ require_relative './jars/mondrian-rest_jars.rb'
6
+
5
7
  require 'mondrian-olap'
6
8
  require 'grape'
7
9
 
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "mondrian-rest"
4
- s.version = '0.6.0'
4
+ s.version = '0.7.0'
5
5
  s.authors = ["Manuel Aristarán"]
6
6
  s.email = ["manuel@jazzido.com"]
7
7
  s.homepage = "https://github.com/jazzido/mondrian-rest"
@@ -12,12 +12,15 @@ Gem::Specification.new do |s|
12
12
  s.platform = 'java'
13
13
 
14
14
  s.files = `git ls-files`.split("\n").reject { |f| f =~ /^spec\// }
15
- s.require_paths = ["lib"]
15
+ s.require_paths = ["lib", "lib/jars"]
16
+
17
+ s.requirements << 'jar no.ssb.jsonstat:json-stat-java, 0.2.2'
16
18
 
17
19
  s.add_runtime_dependency 'mondrian-olap', ["~> 0.8.0"]
18
- s.add_runtime_dependency 'grape', ["~> 0.19.0"]
20
+ s.add_runtime_dependency 'grape', ["~> 1.0.0"]
19
21
  s.add_runtime_dependency 'writeexcel', '~> 1.0', '>= 1.0.5'
20
22
 
23
+ s.add_development_dependency "jar-dependencies", "~> 0.3.2"
21
24
  s.add_development_dependency 'rake'
22
25
  s.add_development_dependency 'rspec'
23
26
  s.add_development_dependency 'jdbc-derby'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mondrian-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: java
6
6
  authors:
7
7
  - Manuel Aristarán
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-22 00:00:00.000000000 Z
11
+ date: 2017-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.19.0
32
+ version: 1.0.0
33
33
  name: grape
34
34
  prerelease: false
35
35
  type: :runtime
@@ -37,7 +37,7 @@ dependencies:
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.19.0
40
+ version: 1.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
@@ -58,6 +58,20 @@ dependencies:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
60
  version: 1.0.5
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: 0.3.2
67
+ name: jar-dependencies
68
+ prerelease: false
69
+ type: :development
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 0.3.2
61
75
  - !ruby/object:Gem::Dependency
62
76
  requirement: !ruby/object:Gem::Requirement
63
77
  requirements:
@@ -154,10 +168,26 @@ files:
154
168
  - Gemfile
155
169
  - README.md
156
170
  - Rakefile
171
+ - lib/jars/com/codepoetics/protonpack/1.9/protonpack-1.9.jar
172
+ - lib/jars/com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar
173
+ - lib/jars/com/fasterxml/jackson/core/jackson-core/2.8.5/jackson-core-2.8.5.jar
174
+ - lib/jars/com/fasterxml/jackson/core/jackson-databind/2.8.5/jackson-databind-2.8.5.jar
175
+ - lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-guava/2.8.5/jackson-datatype-guava-2.8.5.jar
176
+ - lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.8.5/jackson-datatype-jdk8-2.8.5.jar
177
+ - lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.8.5/jackson-datatype-jsr310-2.8.5.jar
178
+ - lib/jars/com/google/guava/guava/19.0/guava-19.0.jar
179
+ - lib/jars/me/yanaga/guava-stream/1.0/guava-stream-1.0.jar
180
+ - lib/jars/mondrian-rest_jars.rb
181
+ - lib/jars/no/ssb/jsonstat/json-stat-java/0.2.2/json-stat-java-0.2.2.jar
157
182
  - lib/mondrian_rest.rb
158
183
  - lib/mondrian_rest/api.rb
159
184
  - lib/mondrian_rest/api_formatters.rb
160
185
  - lib/mondrian_rest/api_helpers.rb
186
+ - lib/mondrian_rest/formatters/aggregation_json.rb
187
+ - lib/mondrian_rest/formatters/csv.rb
188
+ - lib/mondrian_rest/formatters/excel.rb
189
+ - lib/mondrian_rest/formatters/jsonrecords.rb
190
+ - lib/mondrian_rest/formatters/jsonstat.rb
161
191
  - lib/mondrian_rest/mondrian_ext.rb
162
192
  - lib/mondrian_rest/nest.rb
163
193
  - lib/mondrian_rest/query_helper.rb
@@ -171,6 +201,7 @@ post_install_message:
171
201
  rdoc_options: []
172
202
  require_paths:
173
203
  - lib
204
+ - lib/jars
174
205
  required_ruby_version: !ruby/object:Gem::Requirement
175
206
  requirements:
176
207
  - - ">="
@@ -181,7 +212,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
212
  - - ">="
182
213
  - !ruby/object:Gem::Version
183
214
  version: '0'
184
- requirements: []
215
+ requirements:
216
+ - jar no.ssb.jsonstat:json-stat-java, 0.2.2
185
217
  rubyforge_project:
186
218
  rubygems_version: 2.6.8
187
219
  signing_key: