mondrian-rest 0.6.0-java → 0.7.0-java

Sign up to get free protection for your applications and to get access to all the features.
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: