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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/README.md +2 -0
- data/Rakefile +6 -1
- data/lib/jars/com/codepoetics/protonpack/1.9/protonpack-1.9.jar +0 -0
- data/lib/jars/com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar +0 -0
- data/lib/jars/com/fasterxml/jackson/core/jackson-core/2.8.5/jackson-core-2.8.5.jar +0 -0
- data/lib/jars/com/fasterxml/jackson/core/jackson-databind/2.8.5/jackson-databind-2.8.5.jar +0 -0
- data/lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-guava/2.8.5/jackson-datatype-guava-2.8.5.jar +0 -0
- data/lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.8.5/jackson-datatype-jdk8-2.8.5.jar +0 -0
- data/lib/jars/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.8.5/jackson-datatype-jsr310-2.8.5.jar +0 -0
- data/lib/jars/com/google/guava/guava/19.0/guava-19.0.jar +0 -0
- data/lib/jars/me/yanaga/guava-stream/1.0/guava-stream-1.0.jar +0 -0
- data/lib/jars/mondrian-rest_jars.rb +28 -0
- data/lib/jars/no/ssb/jsonstat/json-stat-java/0.2.2/json-stat-java-0.2.2.jar +0 -0
- data/lib/mondrian_rest/api.rb +60 -45
- data/lib/mondrian_rest/api_formatters.rb +6 -76
- data/lib/mondrian_rest/api_helpers.rb +14 -0
- data/lib/mondrian_rest/formatters/aggregation_json.rb +10 -0
- data/lib/mondrian_rest/formatters/csv.rb +21 -0
- data/lib/mondrian_rest/formatters/excel.rb +30 -0
- data/lib/mondrian_rest/formatters/jsonrecords.rb +31 -0
- data/lib/mondrian_rest/formatters/jsonstat.rb +50 -0
- data/lib/mondrian_rest/mondrian_ext.rb +12 -3
- data/lib/mondrian_rest/query_helper.rb +8 -3
- data/lib/mondrian_rest.rb +2 -0
- data/mondrian-rest.gemspec +6 -3
- metadata +37 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9884ded4baf72e8778db0f38bd66689a098ba4c1
|
4
|
+
data.tar.gz: 41004cd22953933eb63c74f335c2ee55b9dfea1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7af0aa6def1e41782c5b517cef5199545a0be1f69baff8400499b5d5f1231f3f5a93d2bfec6a5c8f6f98c83c421ebada332b5e798a8104158721a7430a38ba7f
|
7
|
+
data.tar.gz: 8280d75f3484daba329486853a32aa306ec6b3935511345ad3887405de0b50c1879470e26e4aa2ded4d57426a9744c4cb84aab6d4cf945189294869cd2d0afa2
|
data/.travis.yml
CHANGED
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]
|
Binary file
|
data/lib/jars/com/fasterxml/jackson/core/jackson-annotations/2.8.0/jackson-annotations-2.8.0.jar
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -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
|
data/lib/mondrian_rest/api.rb
CHANGED
@@ -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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
140
|
-
result.caption_properties = params[:caption]
|
141
|
-
result.cube = cube
|
141
|
+
get do
|
142
|
+
run_from_params(params)
|
143
|
+
end
|
142
144
|
|
143
|
-
|
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: /[
|
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
|
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
|
-
|
2
|
-
|
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
|
-
|
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
|
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 ==
|
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}",
|
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.
|
198
|
+
qa.unique_name + '.Members'
|
194
199
|
end
|
195
200
|
end
|
196
201
|
|
data/lib/mondrian_rest.rb
CHANGED
data/mondrian-rest.gemspec
CHANGED
@@ -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.
|
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.
|
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.
|
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-
|
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.
|
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.
|
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:
|